thinkpad-acpi: drop ibm-acpi alias
[linux-2.6] / drivers / s390 / cio / device_pgid.c
1 /*
2  * drivers/s390/cio/device_pgid.c
3  *
4  *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
5  *                       IBM Corporation
6  *    Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
7  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
8  *
9  * Path Group ID functions.
10  */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14
15 #include <asm/ccwdev.h>
16 #include <asm/cio.h>
17 #include <asm/delay.h>
18 #include <asm/lowcore.h>
19
20 #include "cio.h"
21 #include "cio_debug.h"
22 #include "css.h"
23 #include "device.h"
24 #include "ioasm.h"
25 #include "io_sch.h"
26
27 /*
28  * Helper function called from interrupt context to decide whether an
29  * operation should be tried again.
30  */
31 static int __ccw_device_should_retry(union scsw *scsw)
32 {
33         /* CC is only valid if start function bit is set. */
34         if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1)
35                 return 1;
36         /* No more activity. For sense and set PGID we stubbornly try again. */
37         if (!scsw->cmd.actl)
38                 return 1;
39         return 0;
40 }
41
42 /*
43  * Start Sense Path Group ID helper function. Used in ccw_device_recog
44  * and ccw_device_sense_pgid.
45  */
46 static int
47 __ccw_device_sense_pgid_start(struct ccw_device *cdev)
48 {
49         struct subchannel *sch;
50         struct ccw1 *ccw;
51         int ret;
52         int i;
53
54         sch = to_subchannel(cdev->dev.parent);
55         /* Return if we already checked on all paths. */
56         if (cdev->private->imask == 0)
57                 return (sch->lpm == 0) ? -ENODEV : -EACCES;
58         i = 8 - ffs(cdev->private->imask);
59
60         /* Setup sense path group id channel program. */
61         ccw = cdev->private->iccws;
62         ccw->cmd_code = CCW_CMD_SENSE_PGID;
63         ccw->count = sizeof (struct pgid);
64         ccw->flags = CCW_FLAG_SLI;
65
66         /* Reset device status. */
67         memset(&cdev->private->irb, 0, sizeof(struct irb));
68         /* Try on every path. */
69         ret = -ENODEV;
70         while (cdev->private->imask != 0) {
71                 /* Try every path multiple times. */
72                 ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
73                 if (cdev->private->iretry > 0) {
74                         cdev->private->iretry--;
75                         /* Reset internal retry indication. */
76                         cdev->private->flags.intretry = 0;
77                         ret = cio_start (sch, cdev->private->iccws, 
78                                          cdev->private->imask);
79                         /* ret is 0, -EBUSY, -EACCES or -ENODEV */
80                         if (ret != -EACCES)
81                                 return ret;
82                         CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel "
83                                       "0.%x.%04x, lpm %02X, became 'not "
84                                       "operational'\n",
85                                       cdev->private->dev_id.devno,
86                                       sch->schid.ssid,
87                                       sch->schid.sch_no, cdev->private->imask);
88
89                 }
90                 cdev->private->imask >>= 1;
91                 cdev->private->iretry = 5;
92                 i++;
93         }
94
95         return ret;
96 }
97
98 void
99 ccw_device_sense_pgid_start(struct ccw_device *cdev)
100 {
101         int ret;
102
103         /* Set a timeout of 60s */
104         ccw_device_set_timeout(cdev, 60*HZ);
105
106         cdev->private->state = DEV_STATE_SENSE_PGID;
107         cdev->private->imask = 0x80;
108         cdev->private->iretry = 5;
109         memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
110         ret = __ccw_device_sense_pgid_start(cdev);
111         if (ret && ret != -EBUSY)
112                 ccw_device_sense_pgid_done(cdev, ret);
113 }
114
115 /*
116  * Called from interrupt context to check if a valid answer
117  * to Sense Path Group ID was received.
118  */
119 static int
120 __ccw_device_check_sense_pgid(struct ccw_device *cdev)
121 {
122         struct subchannel *sch;
123         struct irb *irb;
124         int i;
125
126         sch = to_subchannel(cdev->dev.parent);
127         irb = &cdev->private->irb;
128         if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
129                 /* Retry Sense PGID if requested. */
130                 if (cdev->private->flags.intretry) {
131                         cdev->private->flags.intretry = 0;
132                         return -EAGAIN;
133                 }
134                 return -ETIME;
135         }
136         if (irb->esw.esw0.erw.cons &&
137             (irb->ecw[0]&(SNS0_CMD_REJECT|SNS0_INTERVENTION_REQ))) {
138                 /*
139                  * If the device doesn't support the Sense Path Group ID
140                  *  command further retries wouldn't help ...
141                  */
142                 return -EOPNOTSUPP;
143         }
144         if (irb->esw.esw0.erw.cons) {
145                 CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, "
146                               "lpum %02X, cnt %02d, sns : "
147                               "%02X%02X%02X%02X %02X%02X%02X%02X ...\n",
148                               cdev->private->dev_id.ssid,
149                               cdev->private->dev_id.devno,
150                               irb->esw.esw0.sublog.lpum,
151                               irb->esw.esw0.erw.scnt,
152                               irb->ecw[0], irb->ecw[1],
153                               irb->ecw[2], irb->ecw[3],
154                               irb->ecw[4], irb->ecw[5],
155                               irb->ecw[6], irb->ecw[7]);
156                 return -EAGAIN;
157         }
158         if (irb->scsw.cmd.cc == 3) {
159                 u8 lpm;
160
161                 lpm = to_io_private(sch)->orb.cmd.lpm;
162                 CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
163                               " lpm %02X, became 'not operational'\n",
164                               cdev->private->dev_id.devno, sch->schid.ssid,
165                               sch->schid.sch_no, lpm);
166                 return -EACCES;
167         }
168         i = 8 - ffs(cdev->private->imask);
169         if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
170                 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
171                               "is reserved by someone else\n",
172                               cdev->private->dev_id.devno, sch->schid.ssid,
173                               sch->schid.sch_no);
174                 return -EUSERS;
175         }
176         return 0;
177 }
178
179 /*
180  * Got interrupt for Sense Path Group ID.
181  */
182 void
183 ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
184 {
185         struct subchannel *sch;
186         struct irb *irb;
187         int ret;
188
189         irb = (struct irb *) __LC_IRB;
190
191         if (irb->scsw.cmd.stctl ==
192             (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
193                 if (__ccw_device_should_retry(&irb->scsw)) {
194                         ret = __ccw_device_sense_pgid_start(cdev);
195                         if (ret && ret != -EBUSY)
196                                 ccw_device_sense_pgid_done(cdev, ret);
197                 }
198                 return;
199         }
200         if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
201                 return;
202         sch = to_subchannel(cdev->dev.parent);
203         ret = __ccw_device_check_sense_pgid(cdev);
204         memset(&cdev->private->irb, 0, sizeof(struct irb));
205         switch (ret) {
206         /* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
207         case -EOPNOTSUPP:       /* Sense Path Group ID not supported */
208                 ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
209                 break;
210         case -ETIME:            /* Sense path group id stopped by timeout. */
211                 ccw_device_sense_pgid_done(cdev, -ETIME);
212                 break;
213         case -EACCES:           /* channel is not operational. */
214                 sch->lpm &= ~cdev->private->imask;
215                 /* Fall through. */
216         case 0:                 /* Sense Path Group ID successful. */
217                 cdev->private->imask >>= 1;
218                 cdev->private->iretry = 5;
219                 /* Fall through. */
220         case -EAGAIN:           /* Try again. */
221                 ret = __ccw_device_sense_pgid_start(cdev);
222                 if (ret != 0 && ret != -EBUSY)
223                         ccw_device_sense_pgid_done(cdev, ret);
224                 break;
225         case -EUSERS:           /* device is reserved for someone else. */
226                 ccw_device_sense_pgid_done(cdev, -EUSERS);
227                 break;
228         }
229 }
230
231 /*
232  * Path Group ID helper function.
233  */
234 static int
235 __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
236 {
237         struct subchannel *sch;
238         struct ccw1 *ccw;
239         int ret;
240
241         sch = to_subchannel(cdev->dev.parent);
242
243         /* Setup sense path group id channel program. */
244         cdev->private->pgid[0].inf.fc = func;
245         ccw = cdev->private->iccws;
246         if (cdev->private->flags.pgid_single)
247                 cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
248         else
249                 cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
250         ccw->cmd_code = CCW_CMD_SET_PGID;
251         ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
252         ccw->count = sizeof (struct pgid);
253         ccw->flags = CCW_FLAG_SLI;
254
255         /* Reset device status. */
256         memset(&cdev->private->irb, 0, sizeof(struct irb));
257
258         /* Try multiple times. */
259         ret = -EACCES;
260         if (cdev->private->iretry > 0) {
261                 cdev->private->iretry--;
262                 /* Reset internal retry indication. */
263                 cdev->private->flags.intretry = 0;
264                 ret = cio_start (sch, cdev->private->iccws,
265                                  cdev->private->imask);
266                 /* We expect an interrupt in case of success or busy
267                  * indication. */
268                 if ((ret == 0) || (ret == -EBUSY))
269                         return ret;
270         }
271         /* PGID command failed on this path. */
272         CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel "
273                       "0.%x.%04x, lpm %02X, became 'not operational'\n",
274                       cdev->private->dev_id.devno, sch->schid.ssid,
275                       sch->schid.sch_no, cdev->private->imask);
276         return ret;
277 }
278
279 /*
280  * Helper function to send a nop ccw down a path.
281  */
282 static int __ccw_device_do_nop(struct ccw_device *cdev)
283 {
284         struct subchannel *sch;
285         struct ccw1 *ccw;
286         int ret;
287
288         sch = to_subchannel(cdev->dev.parent);
289
290         /* Setup nop channel program. */
291         ccw = cdev->private->iccws;
292         ccw->cmd_code = CCW_CMD_NOOP;
293         ccw->cda = 0;
294         ccw->count = 0;
295         ccw->flags = CCW_FLAG_SLI;
296
297         /* Reset device status. */
298         memset(&cdev->private->irb, 0, sizeof(struct irb));
299
300         /* Try multiple times. */
301         ret = -EACCES;
302         if (cdev->private->iretry > 0) {
303                 cdev->private->iretry--;
304                 /* Reset internal retry indication. */
305                 cdev->private->flags.intretry = 0;
306                 ret = cio_start (sch, cdev->private->iccws,
307                                  cdev->private->imask);
308                 /* We expect an interrupt in case of success or busy
309                  * indication. */
310                 if ((ret == 0) || (ret == -EBUSY))
311                         return ret;
312         }
313         /* nop command failed on this path. */
314         CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel "
315                       "0.%x.%04x, lpm %02X, became 'not operational'\n",
316                       cdev->private->dev_id.devno, sch->schid.ssid,
317                       sch->schid.sch_no, cdev->private->imask);
318         return ret;
319 }
320
321
322 /*
323  * Called from interrupt context to check if a valid answer
324  * to Set Path Group ID was received.
325  */
326 static int
327 __ccw_device_check_pgid(struct ccw_device *cdev)
328 {
329         struct subchannel *sch;
330         struct irb *irb;
331
332         sch = to_subchannel(cdev->dev.parent);
333         irb = &cdev->private->irb;
334         if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
335                 /* Retry Set PGID if requested. */
336                 if (cdev->private->flags.intretry) {
337                         cdev->private->flags.intretry = 0;
338                         return -EAGAIN;
339                 }
340                 return -ETIME;
341         }
342         if (irb->esw.esw0.erw.cons) {
343                 if (irb->ecw[0] & SNS0_CMD_REJECT)
344                         return -EOPNOTSUPP;
345                 /* Hmm, whatever happened, try again. */
346                 CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
347                               "cnt %02d, "
348                               "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
349                               cdev->private->dev_id.ssid,
350                               cdev->private->dev_id.devno,
351                               irb->esw.esw0.erw.scnt,
352                               irb->ecw[0], irb->ecw[1],
353                               irb->ecw[2], irb->ecw[3],
354                               irb->ecw[4], irb->ecw[5],
355                               irb->ecw[6], irb->ecw[7]);
356                 return -EAGAIN;
357         }
358         if (irb->scsw.cmd.cc == 3) {
359                 CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
360                               " lpm %02X, became 'not operational'\n",
361                               cdev->private->dev_id.devno, sch->schid.ssid,
362                               sch->schid.sch_no, cdev->private->imask);
363                 return -EACCES;
364         }
365         return 0;
366 }
367
368 /*
369  * Called from interrupt context to check the path status after a nop has
370  * been send.
371  */
372 static int __ccw_device_check_nop(struct ccw_device *cdev)
373 {
374         struct subchannel *sch;
375         struct irb *irb;
376
377         sch = to_subchannel(cdev->dev.parent);
378         irb = &cdev->private->irb;
379         if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
380                 /* Retry NOP if requested. */
381                 if (cdev->private->flags.intretry) {
382                         cdev->private->flags.intretry = 0;
383                         return -EAGAIN;
384                 }
385                 return -ETIME;
386         }
387         if (irb->scsw.cmd.cc == 3) {
388                 CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
389                               " lpm %02X, became 'not operational'\n",
390                               cdev->private->dev_id.devno, sch->schid.ssid,
391                               sch->schid.sch_no, cdev->private->imask);
392                 return -EACCES;
393         }
394         return 0;
395 }
396
397 static void
398 __ccw_device_verify_start(struct ccw_device *cdev)
399 {
400         struct subchannel *sch;
401         __u8 func;
402         int ret;
403
404         sch = to_subchannel(cdev->dev.parent);
405         /* Repeat for all paths. */
406         for (; cdev->private->imask; cdev->private->imask >>= 1,
407                                      cdev->private->iretry = 5) {
408                 if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
409                         /* Path not available, try next. */
410                         continue;
411                 if (cdev->private->options.pgroup) {
412                         if (sch->opm & cdev->private->imask)
413                                 func = SPID_FUNC_ESTABLISH;
414                         else
415                                 func = SPID_FUNC_RESIGN;
416                         ret = __ccw_device_do_pgid(cdev, func);
417                 } else
418                         ret = __ccw_device_do_nop(cdev);
419                 /* We expect an interrupt in case of success or busy
420                  * indication. */
421                 if (ret == 0 || ret == -EBUSY)
422                         return;
423                 /* Permanent path failure, try next. */
424         }
425         /* Done with all paths. */
426         ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
427 }
428                 
429 /*
430  * Got interrupt for Set Path Group ID.
431  */
432 void
433 ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
434 {
435         struct subchannel *sch;
436         struct irb *irb;
437         int ret;
438
439         irb = (struct irb *) __LC_IRB;
440
441         if (irb->scsw.cmd.stctl ==
442             (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
443                 if (__ccw_device_should_retry(&irb->scsw))
444                         __ccw_device_verify_start(cdev);
445                 return;
446         }
447         if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
448                 return;
449         sch = to_subchannel(cdev->dev.parent);
450         if (cdev->private->options.pgroup)
451                 ret = __ccw_device_check_pgid(cdev);
452         else
453                 ret = __ccw_device_check_nop(cdev);
454         memset(&cdev->private->irb, 0, sizeof(struct irb));
455
456         switch (ret) {
457         /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
458         case 0:
459                 /* Path verification ccw finished successfully, update lpm. */
460                 sch->vpm |= sch->opm & cdev->private->imask;
461                 /* Go on with next path. */
462                 cdev->private->imask >>= 1;
463                 cdev->private->iretry = 5;
464                 __ccw_device_verify_start(cdev);
465                 break;
466         case -EOPNOTSUPP:
467                 /*
468                  * One of those strange devices which claim to be able
469                  * to do multipathing but not for Set Path Group ID.
470                  */
471                 if (cdev->private->flags.pgid_single)
472                         cdev->private->options.pgroup = 0;
473                 else
474                         cdev->private->flags.pgid_single = 1;
475                 /* Retry */
476                 sch->vpm = 0;
477                 cdev->private->imask = 0x80;
478                 cdev->private->iretry = 5;
479                 /* fall through. */
480         case -EAGAIN:           /* Try again. */
481                 __ccw_device_verify_start(cdev);
482                 break;
483         case -ETIME:            /* Set path group id stopped by timeout. */
484                 ccw_device_verify_done(cdev, -ETIME);
485                 break;
486         case -EACCES:           /* channel is not operational. */
487                 cdev->private->imask >>= 1;
488                 cdev->private->iretry = 5;
489                 __ccw_device_verify_start(cdev);
490                 break;
491         }
492 }
493
494 void
495 ccw_device_verify_start(struct ccw_device *cdev)
496 {
497         struct subchannel *sch = to_subchannel(cdev->dev.parent);
498
499         cdev->private->flags.pgid_single = 0;
500         cdev->private->imask = 0x80;
501         cdev->private->iretry = 5;
502
503         /* Start with empty vpm. */
504         sch->vpm = 0;
505
506         /* Get current pam. */
507         if (cio_update_schib(sch)) {
508                 ccw_device_verify_done(cdev, -ENODEV);
509                 return;
510         }
511         /* After 60s path verification is considered to have failed. */
512         ccw_device_set_timeout(cdev, 60*HZ);
513         __ccw_device_verify_start(cdev);
514 }
515
516 static void
517 __ccw_device_disband_start(struct ccw_device *cdev)
518 {
519         struct subchannel *sch;
520         int ret;
521
522         sch = to_subchannel(cdev->dev.parent);
523         while (cdev->private->imask != 0) {
524                 if (sch->lpm & cdev->private->imask) {
525                         ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND);
526                         if (ret == 0)
527                                 return;
528                 }
529                 cdev->private->iretry = 5;
530                 cdev->private->imask >>= 1;
531         }
532         ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
533 }
534
535 /*
536  * Got interrupt for Unset Path Group ID.
537  */
538 void
539 ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
540 {
541         struct subchannel *sch;
542         struct irb *irb;
543         int ret;
544
545         irb = (struct irb *) __LC_IRB;
546
547         if (irb->scsw.cmd.stctl ==
548             (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
549                 if (__ccw_device_should_retry(&irb->scsw))
550                         __ccw_device_disband_start(cdev);
551                 return;
552         }
553         if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
554                 return;
555         sch = to_subchannel(cdev->dev.parent);
556         ret = __ccw_device_check_pgid(cdev);
557         memset(&cdev->private->irb, 0, sizeof(struct irb));
558         switch (ret) {
559         /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
560         case 0:                 /* disband successful. */
561                 ccw_device_disband_done(cdev, ret);
562                 break;
563         case -EOPNOTSUPP:
564                 /*
565                  * One of those strange devices which claim to be able
566                  * to do multipathing but not for Unset Path Group ID.
567                  */
568                 cdev->private->flags.pgid_single = 1;
569                 /* fall through. */
570         case -EAGAIN:           /* Try again. */
571                 __ccw_device_disband_start(cdev);
572                 break;
573         case -ETIME:            /* Set path group id stopped by timeout. */
574                 ccw_device_disband_done(cdev, -ETIME);
575                 break;
576         case -EACCES:           /* channel is not operational. */
577                 cdev->private->imask >>= 1;
578                 cdev->private->iretry = 5;
579                 __ccw_device_disband_start(cdev);
580                 break;
581         }
582 }
583
584 void
585 ccw_device_disband_start(struct ccw_device *cdev)
586 {
587         /* After 60s disbanding is considered to have failed. */
588         ccw_device_set_timeout(cdev, 60*HZ);
589
590         cdev->private->flags.pgid_single = 0;
591         cdev->private->iretry = 5;
592         cdev->private->imask = 0x80;
593         __ccw_device_disband_start(cdev);
594 }