xref: /openbmc/linux/drivers/s390/cio/device_pgid.c (revision 96de0e252cedffad61b3cb5e05662c591898e69a)
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 }
597