2 * drivers/s390/cio/device_pgid.c
4 * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
6 * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
7 * Martin Schwidefsky (schwidefsky@de.ibm.com)
9 * Path Group ID functions.
12 #include <linux/module.h>
13 #include <linux/init.h>
15 #include <asm/ccwdev.h>
17 #include <asm/delay.h>
18 #include <asm/lowcore.h>
21 #include "cio_debug.h"
28 * Helper function called from interrupt context to decide whether an
29 * operation should be tried again.
31 static int __ccw_device_should_retry(struct scsw
*scsw
)
33 /* CC is only valid if start function bit is set. */
34 if ((scsw
->fctl
& SCSW_FCTL_START_FUNC
) && scsw
->cc
== 1)
36 /* No more activity. For sense and set PGID we stubbornly try again. */
43 * Start Sense Path Group ID helper function. Used in ccw_device_recog
44 * and ccw_device_sense_pgid.
47 __ccw_device_sense_pgid_start(struct ccw_device
*cdev
)
49 struct subchannel
*sch
;
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
);
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
;
66 /* Reset device status. */
67 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
68 /* Try on every path. */
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 */
82 CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
83 "0.%x.%04x, lpm %02X, became 'not "
85 cdev
->private->dev_id
.devno
,
87 sch
->schid
.sch_no
, cdev
->private->imask
);
90 cdev
->private->imask
>>= 1;
91 cdev
->private->iretry
= 5;
99 ccw_device_sense_pgid_start(struct ccw_device
*cdev
)
103 /* Set a timeout of 60s */
104 ccw_device_set_timeout(cdev
, 60*HZ
);
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
);
116 * Called from interrupt context to check if a valid answer
117 * to Sense Path Group ID was received.
120 __ccw_device_check_sense_pgid(struct ccw_device
*cdev
)
122 struct subchannel
*sch
;
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;
136 if (irb
->esw
.esw0
.erw
.cons
&&
137 (irb
->ecw
[0]&(SNS0_CMD_REJECT
|SNS0_INTERVENTION_REQ
))) {
139 * If the device doesn't support the Sense Path Group ID
140 * command further retries wouldn't help ...
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]);
158 if (irb
->scsw
.cc
== 3) {
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
);
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
,
180 * Got interrupt for Sense Path Group ID.
183 ccw_device_sense_pgid_irq(struct ccw_device
*cdev
, enum dev_event dev_event
)
185 struct subchannel
*sch
;
189 irb
= (struct irb
*) __LC_IRB
;
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
);
200 if (ccw_device_accumulate_and_sense(cdev
, irb
) != 0)
202 sch
= to_subchannel(cdev
->dev
.parent
);
203 ret
= __ccw_device_check_sense_pgid(cdev
);
204 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
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
);
210 case -ETIME
: /* Sense path group id stopped by timeout. */
211 ccw_device_sense_pgid_done(cdev
, -ETIME
);
213 case -EACCES
: /* channel is not operational. */
214 sch
->lpm
&= ~cdev
->private->imask
;
216 case 0: /* Sense Path Group ID successful. */
217 cdev
->private->imask
>>= 1;
218 cdev
->private->iretry
= 5;
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
);
225 case -EUSERS
: /* device is reserved for someone else. */
226 ccw_device_sense_pgid_done(cdev
, -EUSERS
);
232 * Path Group ID helper function.
235 __ccw_device_do_pgid(struct ccw_device
*cdev
, __u8 func
)
237 struct subchannel
*sch
;
241 sch
= to_subchannel(cdev
->dev
.parent
);
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
;
251 ccw
->flags
= CCW_FLAG_SLI
| CCW_FLAG_CC
;
254 cdev
->private->pgid
[0].inf
.fc
|= SPID_FUNC_SINGLE_PATH
;
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
;
261 /* Reset device status. */
262 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
264 /* Try multiple times. */
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
274 if ((ret
== 0) || (ret
== -EBUSY
))
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
);
286 * Helper function to send a nop ccw down a path.
288 static int __ccw_device_do_nop(struct ccw_device
*cdev
)
290 struct subchannel
*sch
;
294 sch
= to_subchannel(cdev
->dev
.parent
);
296 /* Setup nop channel program. */
297 ccw
= cdev
->private->iccws
;
298 ccw
->cmd_code
= CCW_CMD_NOOP
;
301 ccw
->flags
= CCW_FLAG_SLI
;
303 /* Reset device status. */
304 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
306 /* Try multiple times. */
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
316 if ((ret
== 0) || (ret
== -EBUSY
))
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
);
329 * Called from interrupt context to check if a valid answer
330 * to Set Path Group ID was received.
333 __ccw_device_check_pgid(struct ccw_device
*cdev
)
335 struct subchannel
*sch
;
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;
348 if (irb
->esw
.esw0
.erw
.cons
) {
349 if (irb
->ecw
[0] & SNS0_CMD_REJECT
)
351 /* Hmm, whatever happened, try again. */
352 CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
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]);
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
);
375 * Called from interrupt context to check the path status after a nop has
378 static int __ccw_device_check_nop(struct ccw_device
*cdev
)
380 struct subchannel
*sch
;
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;
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
);
404 __ccw_device_verify_start(struct ccw_device
*cdev
)
406 struct subchannel
*sch
;
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. */
417 if (cdev
->private->options
.pgroup
) {
418 if (sch
->opm
& cdev
->private->imask
)
419 func
= SPID_FUNC_ESTABLISH
;
421 func
= SPID_FUNC_RESIGN
;
422 ret
= __ccw_device_do_pgid(cdev
, func
);
424 ret
= __ccw_device_do_nop(cdev
);
425 /* We expect an interrupt in case of success or busy
427 if (ret
== 0 || ret
== -EBUSY
)
429 /* Permanent path failure, try next. */
431 /* Done with all paths. */
432 ccw_device_verify_done(cdev
, (sch
->vpm
!= 0) ? 0 : -ENODEV
);
436 * Got interrupt for Set Path Group ID.
439 ccw_device_verify_irq(struct ccw_device
*cdev
, enum dev_event dev_event
)
441 struct subchannel
*sch
;
445 irb
= (struct irb
*) __LC_IRB
;
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
);
453 if (ccw_device_accumulate_and_sense(cdev
, irb
) != 0)
455 sch
= to_subchannel(cdev
->dev
.parent
);
456 if (cdev
->private->options
.pgroup
)
457 ret
= __ccw_device_check_pgid(cdev
);
459 ret
= __ccw_device_check_nop(cdev
);
460 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
463 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
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
);
474 * One of those strange devices which claim to be able
475 * to do multipathing but not for Set Path Group ID.
477 if (cdev
->private->flags
.pgid_single
)
478 cdev
->private->options
.pgroup
= 0;
480 cdev
->private->flags
.pgid_single
= 1;
483 cdev
->private->imask
= 0x80;
484 cdev
->private->iretry
= 5;
486 case -EAGAIN
: /* Try again. */
487 __ccw_device_verify_start(cdev
);
489 case -ETIME
: /* Set path group id stopped by timeout. */
490 ccw_device_verify_done(cdev
, -ETIME
);
492 case -EACCES
: /* channel is not operational. */
493 cdev
->private->imask
>>= 1;
494 cdev
->private->iretry
= 5;
495 __ccw_device_verify_start(cdev
);
501 ccw_device_verify_start(struct ccw_device
*cdev
)
503 struct subchannel
*sch
= to_subchannel(cdev
->dev
.parent
);
505 cdev
->private->flags
.pgid_single
= 0;
506 cdev
->private->imask
= 0x80;
507 cdev
->private->iretry
= 5;
509 /* Start with empty vpm. */
512 /* Get current pam. */
513 if (stsch(sch
->schid
, &sch
->schib
)) {
514 ccw_device_verify_done(cdev
, -ENODEV
);
517 /* After 60s path verification is considered to have failed. */
518 ccw_device_set_timeout(cdev
, 60*HZ
);
519 __ccw_device_verify_start(cdev
);
523 __ccw_device_disband_start(struct ccw_device
*cdev
)
525 struct subchannel
*sch
;
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
);
535 cdev
->private->iretry
= 5;
536 cdev
->private->imask
>>= 1;
538 ccw_device_disband_done(cdev
, (sch
->lpm
!= 0) ? 0 : -ENODEV
);
542 * Got interrupt for Unset Path Group ID.
545 ccw_device_disband_irq(struct ccw_device
*cdev
, enum dev_event dev_event
)
547 struct subchannel
*sch
;
551 irb
= (struct irb
*) __LC_IRB
;
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
);
559 if (ccw_device_accumulate_and_sense(cdev
, irb
) != 0)
561 sch
= to_subchannel(cdev
->dev
.parent
);
562 ret
= __ccw_device_check_pgid(cdev
);
563 memset(&cdev
->private->irb
, 0, sizeof(struct irb
));
565 /* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
566 case 0: /* disband successful. */
567 ccw_device_disband_done(cdev
, ret
);
571 * One of those strange devices which claim to be able
572 * to do multipathing but not for Unset Path Group ID.
574 cdev
->private->flags
.pgid_single
= 1;
576 case -EAGAIN
: /* Try again. */
577 __ccw_device_disband_start(cdev
);
579 case -ETIME
: /* Set path group id stopped by timeout. */
580 ccw_device_disband_done(cdev
, -ETIME
);
582 case -EACCES
: /* channel is not operational. */
583 cdev
->private->imask
>>= 1;
584 cdev
->private->iretry
= 5;
585 __ccw_device_disband_start(cdev
);
591 ccw_device_disband_start(struct ccw_device
*cdev
)
593 /* After 60s disbanding is considered to have failed. */
594 ccw_device_set_timeout(cdev
, 60*HZ
);
596 cdev
->private->flags
.pgid_single
= 0;
597 cdev
->private->iretry
= 5;
598 cdev
->private->imask
= 0x80;
599 __ccw_device_disband_start(cdev
);