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