- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.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 #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(struct scsw *scsw)
32 {
33         /* CC is only valid if start function bit is set. */
34         if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1)
35                 return 1;
36         /* No more activity. For sense and set PGID we stubbornly try again. */
37         if (!scsw->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(2, "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.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.cc == 3) {
159                 u8 lpm;
160
161                 lpm = to_io_private(sch)->orb.lpm;
162                 CIO_MSG_EVENT(2, "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.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_MULTI_PATH;
248                 ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
249                 ccw->cda = 0;
250                 ccw->count = 0;
251                 ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
252                 ccw++;
253         } else
254                 cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
255
256         ccw->cmd_code = CCW_CMD_SET_PGID;
257         ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
258         ccw->count = sizeof (struct pgid);
259         ccw->flags = CCW_FLAG_SLI;
260
261         /* Reset device status. */
262         memset(&cdev->private->irb, 0, sizeof(struct irb));
263
264         /* Try multiple times. */
265         ret = -EACCES;
266         if (cdev->private->iretry > 0) {
267                 cdev->private->iretry--;
268                 /* Reset internal retry indication. */
269                 cdev->private->flags.intretry = 0;
270                 ret = cio_start (sch, cdev->private->iccws,
271                                  cdev->private->imask);
272                 /* We expect an interrupt in case of success or busy
273                  * indication. */
274                 if ((ret == 0) || (ret == -EBUSY))
275                         return ret;
276         }
277         /* PGID command failed on this path. */
278         CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
279                       "0.%x.%04x, lpm %02X, became 'not operational'\n",
280                       cdev->private->dev_id.devno, sch->schid.ssid,
281                       sch->schid.sch_no, cdev->private->imask);
282         return ret;
283 }
284
285 /*
286  * Helper function to send a nop ccw down a path.
287  */
288 static int __ccw_device_do_nop(struct ccw_device *cdev)
289 {
290         struct subchannel *sch;
291         struct ccw1 *ccw;
292         int ret;
293
294         sch = to_subchannel(cdev->dev.parent);
295
296         /* Setup nop channel program. */
297         ccw = cdev->private->iccws;
298         ccw->cmd_code = CCW_CMD_NOOP;
299         ccw->cda = 0;
300         ccw->count = 0;
301         ccw->flags = CCW_FLAG_SLI;
302
303         /* Reset device status. */
304         memset(&cdev->private->irb, 0, sizeof(struct irb));
305
306         /* Try multiple times. */
307         ret = -EACCES;
308         if (cdev->private->iretry > 0) {
309                 cdev->private->iretry--;
310                 /* Reset internal retry indication. */
311                 cdev->private->flags.intretry = 0;
312                 ret = cio_start (sch, cdev->private->iccws,
313                                  cdev->private->imask);
314                 /* We expect an interrupt in case of success or busy
315                  * indication. */
316                 if ((ret == 0) || (ret == -EBUSY))
317                         return ret;
318         }
319         /* nop command failed on this path. */
320         CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
321                       "0.%x.%04x, lpm %02X, became 'not operational'\n",
322                       cdev->private->dev_id.devno, sch->schid.ssid,
323                       sch->schid.sch_no, cdev->private->imask);
324         return ret;
325 }
326
327
328 /*
329  * Called from interrupt context to check if a valid answer
330  * to Set Path Group ID was received.
331  */
332 static int
333 __ccw_device_check_pgid(struct ccw_device *cdev)
334 {
335         struct subchannel *sch;
336         struct irb *irb;
337
338         sch = to_subchannel(cdev->dev.parent);
339         irb = &cdev->private->irb;
340         if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
341                 /* Retry Set PGID if requested. */
342                 if (cdev->private->flags.intretry) {
343                         cdev->private->flags.intretry = 0;
344                         return -EAGAIN;
345                 }
346                 return -ETIME;
347         }
348         if (irb->esw.esw0.erw.cons) {
349                 if (irb->ecw[0] & SNS0_CMD_REJECT)
350                         return -EOPNOTSUPP;
351                 /* Hmm, whatever happened, try again. */
352                 CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
353                               "cnt %02d, "
354                               "sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
355                               cdev->private->dev_id.ssid,
356                               cdev->private->dev_id.devno,
357                               irb->esw.esw0.erw.scnt,
358                               irb->ecw[0], irb->ecw[1],
359                               irb->ecw[2], irb->ecw[3],
360                               irb->ecw[4], irb->ecw[5],
361                               irb->ecw[6], irb->ecw[7]);
362                 return -EAGAIN;
363         }
364         if (irb->scsw.cc == 3) {
365                 CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x,"
366                               " lpm %02X, became 'not operational'\n",
367                               cdev->private->dev_id.devno, sch->schid.ssid,
368                               sch->schid.sch_no, cdev->private->imask);
369                 return -EACCES;
370         }
371         return 0;
372 }
373
374 /*
375  * Called from interrupt context to check the path status after a nop has
376  * been send.
377  */
378 static int __ccw_device_check_nop(struct ccw_device *cdev)
379 {
380         struct subchannel *sch;
381         struct irb *irb;
382
383         sch = to_subchannel(cdev->dev.parent);
384         irb = &cdev->private->irb;
385         if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) {
386                 /* Retry NOP if requested. */
387                 if (cdev->private->flags.intretry) {
388                         cdev->private->flags.intretry = 0;
389                         return -EAGAIN;
390                 }
391                 return -ETIME;
392         }
393         if (irb->scsw.cc == 3) {
394                 CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
395                               " lpm %02X, became 'not operational'\n",
396                               cdev->private->dev_id.devno, sch->schid.ssid,
397                               sch->schid.sch_no, cdev->private->imask);
398                 return -EACCES;
399         }
400         return 0;
401 }
402
403 static void
404 __ccw_device_verify_start(struct ccw_device *cdev)
405 {
406         struct subchannel *sch;
407         __u8 func;
408         int ret;
409
410         sch = to_subchannel(cdev->dev.parent);
411         /* Repeat for all paths. */
412         for (; cdev->private->imask; cdev->private->imask >>= 1,
413                                      cdev->private->iretry = 5) {
414                 if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
415                         /* Path not available, try next. */
416                         continue;
417                 if (cdev->private->options.pgroup) {
418                         if (sch->opm & cdev->private->imask)
419                                 func = SPID_FUNC_ESTABLISH;
420                         else
421                                 func = SPID_FUNC_RESIGN;
422                         ret = __ccw_device_do_pgid(cdev, func);
423                 } else
424                         ret = __ccw_device_do_nop(cdev);
425                 /* We expect an interrupt in case of success or busy
426                  * indication. */
427                 if (ret == 0 || ret == -EBUSY)
428                         return;
429                 /* Permanent path failure, try next. */
430         }
431         /* Done with all paths. */
432         ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
433 }
434                 
435 /*
436  * Got interrupt for Set Path Group ID.
437  */
438 void
439 ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
440 {
441         struct subchannel *sch;
442         struct irb *irb;
443         int ret;
444
445         irb = (struct irb *) __LC_IRB;
446
447         if (irb->scsw.stctl ==
448             (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
449                 if (__ccw_device_should_retry(&irb->scsw))
450                         __ccw_device_verify_start(cdev);
451                 return;
452         }
453         if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
454                 return;
455         sch = to_subchannel(cdev->dev.parent);
456         if (cdev->private->options.pgroup)
457                 ret = __ccw_device_check_pgid(cdev);
458         else
459                 ret = __ccw_device_check_nop(cdev);
460         memset(&cdev->private->irb, 0, sizeof(struct irb));
461
462         switch (ret) {
463         /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
464         case 0:
465                 /* Path verification ccw finished successfully, update lpm. */
466                 sch->vpm |= sch->opm & cdev->private->imask;
467                 /* Go on with next path. */
468                 cdev->private->imask >>= 1;
469                 cdev->private->iretry = 5;
470                 __ccw_device_verify_start(cdev);
471                 break;
472         case -EOPNOTSUPP:
473                 /*
474                  * One of those strange devices which claim to be able
475                  * to do multipathing but not for Set Path Group ID.
476                  */
477                 if (cdev->private->flags.pgid_single)
478                         cdev->private->options.pgroup = 0;
479                 else
480                         cdev->private->flags.pgid_single = 1;
481                 /* Retry */
482                 sch->vpm = 0;
483                 cdev->private->imask = 0x80;
484                 cdev->private->iretry = 5;
485                 /* fall through. */
486         case -EAGAIN:           /* Try again. */
487                 __ccw_device_verify_start(cdev);
488                 break;
489         case -ETIME:            /* Set path group id stopped by timeout. */
490                 ccw_device_verify_done(cdev, -ETIME);
491                 break;
492         case -EACCES:           /* channel is not operational. */
493                 cdev->private->imask >>= 1;
494                 cdev->private->iretry = 5;
495                 __ccw_device_verify_start(cdev);
496                 break;
497         }
498 }
499
500 void
501 ccw_device_verify_start(struct ccw_device *cdev)
502 {
503         struct subchannel *sch = to_subchannel(cdev->dev.parent);
504
505         cdev->private->flags.pgid_single = 0;
506         cdev->private->imask = 0x80;
507         cdev->private->iretry = 5;
508
509         /* Start with empty vpm. */
510         sch->vpm = 0;
511
512         /* Get current pam. */
513         if (stsch(sch->schid, &sch->schib)) {
514                 ccw_device_verify_done(cdev, -ENODEV);
515                 return;
516         }
517         /* After 60s path verification is considered to have failed. */
518         ccw_device_set_timeout(cdev, 60*HZ);
519         __ccw_device_verify_start(cdev);
520 }
521
522 static void
523 __ccw_device_disband_start(struct ccw_device *cdev)
524 {
525         struct subchannel *sch;
526         int ret;
527
528         sch = to_subchannel(cdev->dev.parent);
529         while (cdev->private->imask != 0) {
530                 if (sch->lpm & cdev->private->imask) {
531                         ret = __ccw_device_do_pgid(cdev, SPID_FUNC_DISBAND);
532                         if (ret == 0)
533                                 return;
534                 }
535                 cdev->private->iretry = 5;
536                 cdev->private->imask >>= 1;
537         }
538         ccw_device_disband_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
539 }
540
541 /*
542  * Got interrupt for Unset Path Group ID.
543  */
544 void
545 ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
546 {
547         struct subchannel *sch;
548         struct irb *irb;
549         int ret;
550
551         irb = (struct irb *) __LC_IRB;
552
553         if (irb->scsw.stctl ==
554             (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
555                 if (__ccw_device_should_retry(&irb->scsw))
556                         __ccw_device_disband_start(cdev);
557                 return;
558         }
559         if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
560                 return;
561         sch = to_subchannel(cdev->dev.parent);
562         ret = __ccw_device_check_pgid(cdev);
563         memset(&cdev->private->irb, 0, sizeof(struct irb));
564         switch (ret) {
565         /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
566         case 0:                 /* disband successful. */
567                 ccw_device_disband_done(cdev, ret);
568                 break;
569         case -EOPNOTSUPP:
570                 /*
571                  * One of those strange devices which claim to be able
572                  * to do multipathing but not for Unset Path Group ID.
573                  */
574                 cdev->private->flags.pgid_single = 1;
575                 /* fall through. */
576         case -EAGAIN:           /* Try again. */
577                 __ccw_device_disband_start(cdev);
578                 break;
579         case -ETIME:            /* Set path group id stopped by timeout. */
580                 ccw_device_disband_done(cdev, -ETIME);
581                 break;
582         case -EACCES:           /* channel is not operational. */
583                 cdev->private->imask >>= 1;
584                 cdev->private->iretry = 5;
585                 __ccw_device_disband_start(cdev);
586                 break;
587         }
588 }
589
590 void
591 ccw_device_disband_start(struct ccw_device *cdev)
592 {
593         /* After 60s disbanding is considered to have failed. */
594         ccw_device_set_timeout(cdev, 60*HZ);
595
596         cdev->private->flags.pgid_single = 0;
597         cdev->private->iretry = 5;
598         cdev->private->imask = 0x80;
599         __ccw_device_disband_start(cdev);
600 }