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