1
2
3
4
5
6
7#include <linux/module.h>
8#include <linux/init.h>
9#include <linux/errno.h>
10#include <linux/slab.h>
11#include <linux/list.h>
12#include <linux/device.h>
13#include <linux/delay.h>
14#include <linux/completion.h>
15
16#include <asm/ccwdev.h>
17#include <asm/idals.h>
18#include <asm/chpid.h>
19#include <asm/fcx.h>
20
21#include "cio.h"
22#include "cio_debug.h"
23#include "css.h"
24#include "chsc.h"
25#include "device.h"
26#include "chp.h"
27
28
29
30
31
32
33
34
35
36
37
38int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
39{
40
41
42
43 if ((flags & CCWDEV_EARLY_NOTIFICATION) &&
44 (flags & CCWDEV_REPORT_ALL))
45 return -EINVAL;
46 cdev->private->options.fast = (flags & CCWDEV_EARLY_NOTIFICATION) != 0;
47 cdev->private->options.repall = (flags & CCWDEV_REPORT_ALL) != 0;
48 cdev->private->options.pgroup = (flags & CCWDEV_DO_PATHGROUP) != 0;
49 cdev->private->options.force = (flags & CCWDEV_ALLOW_FORCE) != 0;
50 cdev->private->options.mpath = (flags & CCWDEV_DO_MULTIPATH) != 0;
51 return 0;
52}
53
54
55
56
57
58
59
60
61
62
63int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
64{
65
66
67
68 if (((flags & CCWDEV_EARLY_NOTIFICATION) &&
69 (flags & CCWDEV_REPORT_ALL)) ||
70 ((flags & CCWDEV_EARLY_NOTIFICATION) &&
71 cdev->private->options.repall) ||
72 ((flags & CCWDEV_REPORT_ALL) &&
73 cdev->private->options.fast))
74 return -EINVAL;
75 cdev->private->options.fast |= (flags & CCWDEV_EARLY_NOTIFICATION) != 0;
76 cdev->private->options.repall |= (flags & CCWDEV_REPORT_ALL) != 0;
77 cdev->private->options.pgroup |= (flags & CCWDEV_DO_PATHGROUP) != 0;
78 cdev->private->options.force |= (flags & CCWDEV_ALLOW_FORCE) != 0;
79 cdev->private->options.mpath |= (flags & CCWDEV_DO_MULTIPATH) != 0;
80 return 0;
81}
82
83
84
85
86
87
88
89
90void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
91{
92 cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
93 cdev->private->options.repall &= (flags & CCWDEV_REPORT_ALL) == 0;
94 cdev->private->options.pgroup &= (flags & CCWDEV_DO_PATHGROUP) == 0;
95 cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
96 cdev->private->options.mpath &= (flags & CCWDEV_DO_MULTIPATH) == 0;
97}
98
99
100
101
102
103
104
105int ccw_device_is_pathgroup(struct ccw_device *cdev)
106{
107 return cdev->private->flags.pgroup;
108}
109EXPORT_SYMBOL(ccw_device_is_pathgroup);
110
111
112
113
114
115
116
117int ccw_device_is_multipath(struct ccw_device *cdev)
118{
119 return cdev->private->flags.mpath;
120}
121EXPORT_SYMBOL(ccw_device_is_multipath);
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
139{
140 struct subchannel *sch;
141 int ret;
142
143 if (!cdev || !cdev->dev.parent)
144 return -ENODEV;
145 sch = to_subchannel(cdev->dev.parent);
146 if (!sch->schib.pmcw.ena)
147 return -EINVAL;
148 if (cdev->private->state == DEV_STATE_NOT_OPER)
149 return -ENODEV;
150 if (cdev->private->state != DEV_STATE_ONLINE &&
151 cdev->private->state != DEV_STATE_W4SENSE)
152 return -EINVAL;
153
154 ret = cio_clear(sch);
155 if (ret == 0)
156 cdev->private->intparm = intparm;
157 return ret;
158}
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
185 unsigned long intparm, __u8 lpm, __u8 key,
186 unsigned long flags)
187{
188 struct subchannel *sch;
189 int ret;
190
191 if (!cdev || !cdev->dev.parent)
192 return -ENODEV;
193 sch = to_subchannel(cdev->dev.parent);
194 if (!sch->schib.pmcw.ena)
195 return -EINVAL;
196 if (cdev->private->state == DEV_STATE_NOT_OPER)
197 return -ENODEV;
198 if (cdev->private->state == DEV_STATE_VERIFY) {
199
200 if (!cdev->private->flags.fake_irb) {
201 cdev->private->flags.fake_irb = FAKE_CMD_IRB;
202 cdev->private->intparm = intparm;
203 return 0;
204 } else
205
206 return -EBUSY;
207 }
208 if (cdev->private->state != DEV_STATE_ONLINE ||
209 ((sch->schib.scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) &&
210 !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)) ||
211 cdev->private->flags.doverify)
212 return -EBUSY;
213 ret = cio_set_options (sch, flags);
214 if (ret)
215 return ret;
216
217 if (lpm) {
218 lpm &= sch->lpm;
219 if (lpm == 0)
220 return -EACCES;
221 }
222 ret = cio_start_key (sch, cpa, lpm, key);
223 switch (ret) {
224 case 0:
225 cdev->private->intparm = intparm;
226 break;
227 case -EACCES:
228 case -ENODEV:
229 dev_fsm_event(cdev, DEV_EVENT_VERIFY);
230 break;
231 }
232 return ret;
233}
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
265 unsigned long intparm, __u8 lpm, __u8 key,
266 unsigned long flags, int expires)
267{
268 int ret;
269
270 if (!cdev)
271 return -ENODEV;
272 ccw_device_set_timeout(cdev, expires);
273 ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags);
274 if (ret != 0)
275 ccw_device_set_timeout(cdev, 0);
276 return ret;
277}
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
303 unsigned long intparm, __u8 lpm, unsigned long flags)
304{
305 return ccw_device_start_key(cdev, cpa, intparm, lpm,
306 PAGE_DEFAULT_KEY, flags);
307}
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
338 unsigned long intparm, __u8 lpm,
339 unsigned long flags, int expires)
340{
341 return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
342 PAGE_DEFAULT_KEY, flags,
343 expires);
344}
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
364{
365 struct subchannel *sch;
366 int ret;
367
368 if (!cdev || !cdev->dev.parent)
369 return -ENODEV;
370 sch = to_subchannel(cdev->dev.parent);
371 if (!sch->schib.pmcw.ena)
372 return -EINVAL;
373 if (cdev->private->state == DEV_STATE_NOT_OPER)
374 return -ENODEV;
375 if (cdev->private->state != DEV_STATE_ONLINE &&
376 cdev->private->state != DEV_STATE_W4SENSE)
377 return -EINVAL;
378
379 ret = cio_halt(sch);
380 if (ret == 0)
381 cdev->private->intparm = intparm;
382 return ret;
383}
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398int ccw_device_resume(struct ccw_device *cdev)
399{
400 struct subchannel *sch;
401
402 if (!cdev || !cdev->dev.parent)
403 return -ENODEV;
404 sch = to_subchannel(cdev->dev.parent);
405 if (!sch->schib.pmcw.ena)
406 return -EINVAL;
407 if (cdev->private->state == DEV_STATE_NOT_OPER)
408 return -ENODEV;
409 if (cdev->private->state != DEV_STATE_ONLINE ||
410 !(sch->schib.scsw.cmd.actl & SCSW_ACTL_SUSPENDED))
411 return -EINVAL;
412 return cio_resume(sch);
413}
414
415
416
417
418int
419ccw_device_call_handler(struct ccw_device *cdev)
420{
421 unsigned int stctl;
422 int ending_status;
423
424
425
426
427
428
429
430
431
432 stctl = scsw_stctl(&cdev->private->irb.scsw);
433 ending_status = (stctl & SCSW_STCTL_SEC_STATUS) ||
434 (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) ||
435 (stctl == SCSW_STCTL_STATUS_PEND);
436 if (!ending_status &&
437 !cdev->private->options.repall &&
438 !(stctl & SCSW_STCTL_INTER_STATUS) &&
439 !(cdev->private->options.fast &&
440 (stctl & SCSW_STCTL_PRIM_STATUS)))
441 return 0;
442
443
444 if (ending_status)
445 ccw_device_set_timeout(cdev, 0);
446
447
448
449 if (cdev->handler)
450 cdev->handler(cdev, cdev->private->intparm,
451 &cdev->private->irb);
452
453
454
455
456 memset(&cdev->private->irb, 0, sizeof(struct irb));
457
458 return 1;
459}
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
476{
477 int ciw_cnt;
478
479 if (cdev->private->flags.esid == 0)
480 return NULL;
481 for (ciw_cnt = 0; ciw_cnt < MAX_CIWS; ciw_cnt++)
482 if (cdev->private->senseid.ciw[ciw_cnt].ct == ct)
483 return cdev->private->senseid.ciw + ciw_cnt;
484 return NULL;
485}
486
487
488
489
490
491
492
493
494__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
495{
496 struct subchannel *sch;
497
498 if (!cdev->dev.parent)
499 return 0;
500
501 sch = to_subchannel(cdev->dev.parent);
502 return sch->lpm;
503}
504
505struct stlck_data {
506 struct completion done;
507 int rc;
508};
509
510void ccw_device_stlck_done(struct ccw_device *cdev, void *data, int rc)
511{
512 struct stlck_data *sdata = data;
513
514 sdata->rc = rc;
515 complete(&sdata->done);
516}
517
518
519
520
521int ccw_device_stlck(struct ccw_device *cdev)
522{
523 struct subchannel *sch = to_subchannel(cdev->dev.parent);
524 struct stlck_data data;
525 u8 *buffer;
526 int rc;
527
528
529 if (cdev->drv) {
530 if (!cdev->private->options.force)
531 return -EINVAL;
532 }
533 buffer = kzalloc(64, GFP_DMA | GFP_KERNEL);
534 if (!buffer)
535 return -ENOMEM;
536 init_completion(&data.done);
537 data.rc = -EIO;
538 spin_lock_irq(sch->lock);
539 rc = cio_enable_subchannel(sch, (u32) (addr_t) sch);
540 if (rc)
541 goto out_unlock;
542
543 cdev->private->state = DEV_STATE_STEAL_LOCK,
544 ccw_device_stlck_start(cdev, &data, &buffer[0], &buffer[32]);
545 spin_unlock_irq(sch->lock);
546
547 if (wait_for_completion_interruptible(&data.done)) {
548
549 spin_lock_irq(sch->lock);
550 ccw_request_cancel(cdev);
551 spin_unlock_irq(sch->lock);
552 wait_for_completion(&data.done);
553 }
554 rc = data.rc;
555
556 spin_lock_irq(sch->lock);
557 cio_disable_subchannel(sch);
558 cdev->private->state = DEV_STATE_BOXED;
559out_unlock:
560 spin_unlock_irq(sch->lock);
561 kfree(buffer);
562
563 return rc;
564}
565
566void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
567{
568 struct subchannel *sch;
569 struct chp_id chpid;
570
571 sch = to_subchannel(cdev->dev.parent);
572 chp_id_init(&chpid);
573 chpid.id = sch->schib.pmcw.chpid[chp_no];
574 return chp_get_chp_desc(chpid);
575}
576
577
578
579
580
581
582void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id)
583{
584 *dev_id = cdev->private->dev_id;
585}
586EXPORT_SYMBOL(ccw_device_get_id);
587
588
589
590
591
592
593
594
595
596
597
598
599int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
600 unsigned long intparm, u8 lpm, u8 key)
601{
602 struct subchannel *sch;
603 int rc;
604
605 sch = to_subchannel(cdev->dev.parent);
606 if (!sch->schib.pmcw.ena)
607 return -EINVAL;
608 if (cdev->private->state == DEV_STATE_VERIFY) {
609
610 if (!cdev->private->flags.fake_irb) {
611 cdev->private->flags.fake_irb = FAKE_TM_IRB;
612 cdev->private->intparm = intparm;
613 return 0;
614 } else
615
616 return -EBUSY;
617 }
618 if (cdev->private->state != DEV_STATE_ONLINE)
619 return -EIO;
620
621 if (lpm) {
622 lpm &= sch->lpm;
623 if (lpm == 0)
624 return -EACCES;
625 }
626 rc = cio_tm_start_key(sch, tcw, lpm, key);
627 if (rc == 0)
628 cdev->private->intparm = intparm;
629 return rc;
630}
631EXPORT_SYMBOL(ccw_device_tm_start_key);
632
633
634
635
636
637
638
639
640
641
642
643
644
645int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
646 unsigned long intparm, u8 lpm, u8 key,
647 int expires)
648{
649 int ret;
650
651 ccw_device_set_timeout(cdev, expires);
652 ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key);
653 if (ret != 0)
654 ccw_device_set_timeout(cdev, 0);
655 return ret;
656}
657EXPORT_SYMBOL(ccw_device_tm_start_timeout_key);
658
659
660
661
662
663
664
665
666
667
668
669int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw,
670 unsigned long intparm, u8 lpm)
671{
672 return ccw_device_tm_start_key(cdev, tcw, intparm, lpm,
673 PAGE_DEFAULT_KEY);
674}
675EXPORT_SYMBOL(ccw_device_tm_start);
676
677
678
679
680
681
682
683
684
685
686
687
688int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw,
689 unsigned long intparm, u8 lpm, int expires)
690{
691 return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm,
692 PAGE_DEFAULT_KEY, expires);
693}
694EXPORT_SYMBOL(ccw_device_tm_start_timeout);
695
696
697
698
699
700
701
702
703
704int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
705{
706 struct subchannel *sch = to_subchannel(cdev->dev.parent);
707 struct channel_path *chp;
708 struct chp_id chpid;
709 int mdc = 0, i;
710
711
712 if (mask)
713 mask &= sch->lpm;
714 else
715 mask = sch->lpm;
716
717 chp_id_init(&chpid);
718 for (i = 0; i < 8; i++) {
719 if (!(mask & (0x80 >> i)))
720 continue;
721 chpid.id = sch->schib.pmcw.chpid[i];
722 chp = chpid_to_chp(chpid);
723 if (!chp)
724 continue;
725
726 mutex_lock(&chp->lock);
727 if (!chp->desc_fmt1.f) {
728 mutex_unlock(&chp->lock);
729 return 0;
730 }
731 if (!chp->desc_fmt1.r)
732 mdc = 1;
733 mdc = mdc ? min_t(int, mdc, chp->desc_fmt1.mdc) :
734 chp->desc_fmt1.mdc;
735 mutex_unlock(&chp->lock);
736 }
737
738 return mdc;
739}
740EXPORT_SYMBOL(ccw_device_get_mdc);
741
742
743
744
745
746
747
748
749int ccw_device_tm_intrg(struct ccw_device *cdev)
750{
751 struct subchannel *sch = to_subchannel(cdev->dev.parent);
752
753 if (!sch->schib.pmcw.ena)
754 return -EINVAL;
755 if (cdev->private->state != DEV_STATE_ONLINE)
756 return -EIO;
757 if (!scsw_is_tm(&sch->schib.scsw) ||
758 !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_START_PEND))
759 return -EINVAL;
760 return cio_tm_intrg(sch);
761}
762EXPORT_SYMBOL(ccw_device_tm_intrg);
763
764
765
766
767
768
769void ccw_device_get_schid(struct ccw_device *cdev, struct subchannel_id *schid)
770{
771 struct subchannel *sch = to_subchannel(cdev->dev.parent);
772
773 *schid = sch->schid;
774}
775EXPORT_SYMBOL_GPL(ccw_device_get_schid);
776
777MODULE_LICENSE("GPL");
778EXPORT_SYMBOL(ccw_device_set_options_mask);
779EXPORT_SYMBOL(ccw_device_set_options);
780EXPORT_SYMBOL(ccw_device_clear_options);
781EXPORT_SYMBOL(ccw_device_clear);
782EXPORT_SYMBOL(ccw_device_halt);
783EXPORT_SYMBOL(ccw_device_resume);
784EXPORT_SYMBOL(ccw_device_start_timeout);
785EXPORT_SYMBOL(ccw_device_start);
786EXPORT_SYMBOL(ccw_device_start_timeout_key);
787EXPORT_SYMBOL(ccw_device_start_key);
788EXPORT_SYMBOL(ccw_device_get_ciw);
789EXPORT_SYMBOL(ccw_device_get_path_mask);
790EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
791