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