xref: /illumos-gate/usr/src/uts/common/io/scsi/adapters/scsi_vhci/fops/tpgs.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Implementation of "scsi_vhci_f_tpgs" T10 standard based failover_ops.
28  *
29  * NOTE: for non-sequential devices only.
30  */
31 
32 #include <sys/conf.h>
33 #include <sys/file.h>
34 #include <sys/ddi.h>
35 #include <sys/sunddi.h>
36 #include <sys/scsi/scsi.h>
37 #include <sys/scsi/adapters/scsi_vhci.h>
38 #include <sys/scsi/adapters/scsi_vhci_tpgs.h>
39 
40 /* Supported device table entries.  */
41 char	*std_dev_table[] = { NULL };
42 
43 /* Failover module plumbing. */
44 SCSI_FAILOVER_OP(SFO_NAME_TPGS, std);
45 
46 #define	STD_FO_CMD_RETRY_DELAY	1000000 /* 1 seconds */
47 #define	STD_FO_RETRY_DELAY	2000000 /* 2 seconds */
48 /*
49  * max time for failover to complete is 3 minutes.  Compute
50  * number of retries accordingly, to ensure we wait for at least
51  * 3 minutes
52  */
53 #define	STD_FO_MAX_RETRIES	(3*60*1000000)/STD_FO_RETRY_DELAY
54 
55 
56 /* ARGSUSED */
57 static int
58 std_device_probe(struct scsi_device *sd, struct scsi_inquiry *inq,
59     void **ctpriv)
60 {
61 	int		mode, state, xlf, preferred = 0;
62 
63 	VHCI_DEBUG(6, (CE_NOTE, NULL, "std_device_probe: vidpid %s\n",
64 	    inq->inq_vid));
65 
66 	if (inq->inq_tpgs == TPGS_FAILOVER_NONE) {
67 		VHCI_DEBUG(4, (CE_WARN, NULL,
68 		    "!std_device_probe: not a standard tpgs device"));
69 		return (SFO_DEVICE_PROBE_PHCI);
70 	}
71 
72 	if (inq->inq_dtype == DTYPE_SEQUENTIAL) {
73 		VHCI_DEBUG(4, (CE_NOTE, NULL,
74 		    "!std_device_probe: Detected a "
75 		    "Standard Asymmetric device "
76 		    "not yet supported\n"));
77 		return (SFO_DEVICE_PROBE_PHCI);
78 	}
79 
80 	if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) {
81 		VHCI_DEBUG(4, (CE_WARN, NULL, "!unable to fetch fo "
82 		    "mode: sd(%p)", (void *) sd));
83 		return (SFO_DEVICE_PROBE_PHCI);
84 	}
85 
86 	if (inq->inq_tpgs == TPGS_FAILOVER_IMPLICIT) {
87 		VHCI_DEBUG(1, (CE_NOTE, NULL,
88 		    "!std_device_probe: Detected a "
89 		    "Standard Asymmetric device "
90 		    "with implicit failover\n"));
91 		return (SFO_DEVICE_PROBE_VHCI);
92 	}
93 	if (inq->inq_tpgs == TPGS_FAILOVER_EXPLICIT) {
94 		VHCI_DEBUG(1, (CE_NOTE, NULL,
95 		    "!std_device_probe: Detected a "
96 		    "Standard Asymmetric device "
97 		    "with explicit failover\n"));
98 		return (SFO_DEVICE_PROBE_VHCI);
99 	}
100 	if (inq->inq_tpgs == TPGS_FAILOVER_BOTH) {
101 		VHCI_DEBUG(1, (CE_NOTE, NULL,
102 		    "!std_device_probe: Detected a "
103 		    "Standard Asymmetric device "
104 		    "which supports both implicit and explicit failover\n"));
105 		return (SFO_DEVICE_PROBE_VHCI);
106 	}
107 	VHCI_DEBUG(1, (CE_WARN, NULL,
108 	    "!std_device_probe: "
109 	    "Unknown tpgs_bits: %x", inq->inq_tpgs));
110 	return (SFO_DEVICE_PROBE_PHCI);
111 }
112 
113 /* ARGSUSED */
114 static void
115 std_device_unprobe(struct scsi_device *sd, void *ctpriv)
116 {
117 	/*
118 	 * For future use
119 	 */
120 }
121 
122 /* ARGSUSED */
123 static int
124 std_activate_explicit(struct scsi_device *sd, int xlf_capable)
125 {
126 	cmn_err(CE_NOTE, "Explicit Activation is done by "
127 	    "vhci_tpgs_set_target_groups() call from MPAPI");
128 	return (1);
129 }
130 
131 /*
132  * Process the packet reason of CMD_PKT_CMPLT - return 0 if no
133  * retry and 1 if a retry should be done
134  */
135 static int
136 std_process_cmplt_pkt(struct scsi_device *sd, struct scsi_pkt *pkt,
137     int *retry_cnt, int *retval)
138 {
139 	*retval = 1; /* fail */
140 
141 	switch (SCBP_C(pkt)) {
142 		case STATUS_GOOD:
143 			*retval = 0;
144 			break;
145 		case STATUS_CHECK:
146 			if (pkt->pkt_state & STATE_ARQ_DONE) {
147 				uint8_t *sns, skey, asc, ascq;
148 				sns = (uint8_t *)
149 				    &(((struct scsi_arq_status *)(uintptr_t)
150 				    (pkt->pkt_scbp))->sts_sensedata);
151 				skey = scsi_sense_key(sns);
152 				asc = scsi_sense_asc(sns);
153 				ascq = scsi_sense_ascq(sns);
154 				if (skey == KEY_UNIT_ATTENTION) {
155 					/*
156 					 * tpgs access state changed
157 					 */
158 					if (asc == STD_SCSI_ASC_STATE_CHG &&
159 					    ascq ==
160 					    STD_SCSI_ASCQ_STATE_CHG_SUCC) {
161 						/* XXX: update path info? */
162 						cmn_err(CE_WARN,
163 						    "!Device failover"
164 						    " state change");
165 					}
166 					return (1);
167 				} else if (skey == KEY_NOT_READY) {
168 					if (asc ==
169 					    STD_LOGICAL_UNIT_NOT_ACCESSIBLE &&
170 					    ascq == STD_TGT_PORT_STANDBY) {
171 						/*
172 						 * Don't retry on the path
173 						 * which is indicated as
174 						 * standby, return failure.
175 						 */
176 						return (0);
177 					} else if ((*retry_cnt)++ >=
178 					    STD_FO_MAX_RETRIES) {
179 						cmn_err(CE_WARN,
180 						    "!Device failover failed: "
181 						    "timed out waiting for "
182 						    "path to become active");
183 						return (0);
184 					}
185 					VHCI_DEBUG(6, (CE_NOTE, NULL,
186 					    "!(sd:%p)lun becoming active...\n",
187 					    (void *)sd));
188 					drv_usecwait(STD_FO_RETRY_DELAY);
189 					return (1);
190 				}
191 				cmn_err(CE_NOTE, "!Failover failed;"
192 				    " sense key:%x, ASC: %x, "
193 				    "ASCQ:%x", skey, asc, ascq);
194 				return (0);
195 			}
196 			VHCI_DEBUG(4, (CE_WARN, NULL,
197 			    "!(sd:%p):"
198 			    " status returned CHECK during std"
199 			    " path activation", (void *)sd));
200 			return (0);
201 		case STATUS_QFULL:
202 			VHCI_DEBUG(6, (CE_NOTE, NULL, "QFULL "
203 			    "status returned QFULL during std "
204 			    "path activation for %p\n", (void *)sd));
205 			drv_usecwait(5000);
206 			return (1);
207 		case STATUS_BUSY:
208 			VHCI_DEBUG(6, (CE_NOTE, NULL, "BUSY "
209 			    "status returned BUSY during std "
210 			    "path activation for %p\n", (void *)sd));
211 			drv_usecwait(5000);
212 			return (1);
213 		default:
214 			VHCI_DEBUG(4, (CE_WARN, NULL,
215 			    "!(sd:%p) Bad status returned during std "
216 			    "activation (pkt %p, status %x)",
217 			    (void *)sd, (void *)pkt, SCBP_C(pkt)));
218 			return (0);
219 	}
220 	return (0);
221 }
222 
223 /*
224  * For now we are going to use primary/online and secondary/online.
225  * There is no standby path returned by the dsp and we may have
226  * to do something different for other devices that use standby
227  */
228 /* ARGSUSED */
229 static int
230 std_path_activate(struct scsi_device *sd, char *pathclass,
231     void *ctpriv)
232 {
233 	struct buf			*bp;
234 	struct scsi_pkt			*pkt;
235 	struct scsi_address		*ap;
236 	int				err, retry_cnt, retry_cmd_cnt;
237 	int				mode, state, retval, xlf, preferred;
238 
239 	ap = &sd->sd_address;
240 
241 	mode = state = 0;
242 
243 	if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) {
244 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_path_activate:"
245 		    " failed vhci_tpgs_get_target_fo_mode\n"));
246 		return (1);
247 	}
248 	if ((state == STD_ACTIVE_OPTIMIZED) ||
249 	    (state == STD_ACTIVE_NONOPTIMIZED)) {
250 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!path already active for %p\n",
251 		    (void *)sd));
252 		return (0);
253 	}
254 
255 	if (mode == SCSI_EXPLICIT_FAILOVER) {
256 		VHCI_DEBUG(4, (CE_NOTE, NULL,
257 		    "!mode is EXPLICIT for %p xlf %x\n",
258 		    (void *)sd, xlf));
259 		retval = std_activate_explicit(sd, xlf);
260 		if (retval != 0) {
261 			VHCI_DEBUG(4, (CE_NOTE, NULL,
262 			    "!(sd:%p)std_path_activate failed(1)\n",
263 			    (void *)sd));
264 			return (1);
265 		}
266 	} else {
267 		VHCI_DEBUG(4, (CE_NOTE, NULL, "STD mode is IMPLICIT for %p\n",
268 		    (void *)sd));
269 	}
270 
271 	bp = scsi_alloc_consistent_buf(ap, (struct buf *)NULL, DEV_BSIZE,
272 	    B_READ, NULL, NULL);
273 	if (!bp) {
274 		VHCI_DEBUG(4, (CE_WARN, NULL,
275 		    "!(sd:%p)std_path_activate failed to alloc buffer",
276 		    (void *)sd));
277 		return (1);
278 	}
279 
280 	pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP1,
281 	    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT, NULL, NULL);
282 	if (!pkt) {
283 		VHCI_DEBUG(4, (CE_WARN, NULL,
284 		    "!(sd:%p)std_path_activate failed to initialize packet",
285 		    (void *)sd));
286 		scsi_free_consistent_buf(bp);
287 		return (1);
288 	}
289 
290 	(void) scsi_setup_cdb((union scsi_cdb *)(uintptr_t)pkt->pkt_cdbp,
291 	    SCMD_READ, 1, 1, 0);
292 	pkt->pkt_time = 3*30;
293 	pkt->pkt_flags |= FLAG_NOINTR;
294 
295 	retry_cnt = 0;
296 	retry_cmd_cnt = 0;
297 retry:
298 	err = scsi_transport(pkt);
299 	if (err != TRAN_ACCEPT) {
300 		/*
301 		 * Retry TRAN_BUSY till STD_FO_MAX_RETRIES is exhausted.
302 		 * All other errors are fatal and should not be retried.
303 		 */
304 		if ((err == TRAN_BUSY) &&
305 		    (retry_cnt++ < STD_FO_MAX_RETRIES)) {
306 			drv_usecwait(STD_FO_RETRY_DELAY);
307 			goto retry;
308 		}
309 		cmn_err(CE_WARN, "Failover failed, "
310 		    "couldn't transport packet");
311 		scsi_destroy_pkt(pkt);
312 		scsi_free_consistent_buf(bp);
313 		return (1);
314 	}
315 	switch (pkt->pkt_reason) {
316 		case CMD_CMPLT:
317 			/*
318 			 * Re-initialize retry_cmd_cnt. Allow transport and
319 			 * cmd errors to go through a full retry count when
320 			 * these are encountered.  This way TRAN/CMD errors
321 			 * retry count is not exhausted due to CMD_CMPLTs
322 			 * delay. This allows the system
323 			 * to brave a hick-up on the link at any given time,
324 			 * while waiting for the fo to complete.
325 			 */
326 			retry_cmd_cnt = 0;
327 			if (std_process_cmplt_pkt(sd, pkt, &retry_cnt,
328 			    &retval) != 0) {
329 				goto retry;
330 			}
331 			break;
332 		case CMD_TIMEOUT:
333 			cmn_err(CE_WARN, "!Failover failed: timed out ");
334 			retval = 1;
335 			break;
336 		case CMD_INCOMPLETE:
337 		case CMD_RESET:
338 		case CMD_ABORTED:
339 		case CMD_TRAN_ERR:
340 			/*
341 			 * Increased the number of retries when these error
342 			 * cases are encountered.  Also added a 1 sec wait
343 			 * before retrying.
344 			 */
345 			if (retry_cmd_cnt++ < STD_FO_MAX_CMD_RETRIES) {
346 				drv_usecwait(STD_FO_CMD_RETRY_DELAY);
347 				VHCI_DEBUG(4, (CE_WARN, NULL,
348 				    "!Retrying path activation due to "
349 				    "pkt reason:%x, retry cnt:%d",
350 				    pkt->pkt_reason, retry_cmd_cnt));
351 				goto retry;
352 			}
353 			/* FALLTHROUGH */
354 		default:
355 			cmn_err(CE_WARN, "!Path activation did not "
356 			    "complete successfully,"
357 			    "(pkt reason %x)", pkt->pkt_reason);
358 			retval = 1;
359 			break;
360 	}
361 
362 	scsi_destroy_pkt(pkt);
363 	scsi_free_consistent_buf(bp);
364 	return (retval);
365 }
366 
367 /* ARGSUSED */
368 static int std_path_deactivate(struct scsi_device *sd, char *pathclass,
369     void *ctpriv)
370 {
371 	return (0);
372 }
373 
374 /* ARGSUSED */
375 static int
376 std_path_get_opinfo(struct scsi_device *sd, struct scsi_path_opinfo *opinfo,
377     void *ctpriv)
378 {
379 	int			mode, preferred, state, xlf;
380 
381 	opinfo->opinfo_rev = OPINFO_REV;
382 
383 	if (vhci_tpgs_get_target_fo_mode(sd, &mode, &state, &xlf, &preferred)) {
384 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_path_getopinfo:"
385 		    " failed vhci_tpgs_get_target_fo_mode\n"));
386 		return (1);
387 	}
388 
389 	if (state == STD_ACTIVE_OPTIMIZED) {
390 		opinfo->opinfo_path_state = SCSI_PATH_ACTIVE;
391 	} else if (state == STD_ACTIVE_NONOPTIMIZED) {
392 		opinfo->opinfo_path_state = SCSI_PATH_ACTIVE_NONOPT;
393 	} else if (state == STD_STANDBY) {
394 		opinfo->opinfo_path_state = SCSI_PATH_INACTIVE;
395 	} else if (state == STD_UNAVAILABLE) {
396 		opinfo->opinfo_path_state = SCSI_PATH_INACTIVE;
397 	}
398 	if (preferred) {
399 		(void) strcpy(opinfo->opinfo_path_attr, PCLASS_PRIMARY);
400 	} else {
401 		(void) strcpy(opinfo->opinfo_path_attr, PCLASS_SECONDARY);
402 	}
403 	VHCI_DEBUG(4, (CE_NOTE, NULL, "std_path_get_opinfo: "
404 	    "class: %s state: %s\n", opinfo->opinfo_path_attr,
405 	    opinfo->opinfo_path_state == SCSI_PATH_ACTIVE ?
406 	    "ACTIVE" : "INACTIVE"));
407 	opinfo->opinfo_xlf_capable = 0;
408 	opinfo->opinfo_pswtch_best = 30;
409 	opinfo->opinfo_pswtch_worst = 3*30;
410 	opinfo->opinfo_preferred = (uint16_t)preferred;
411 	opinfo->opinfo_mode = (uint16_t)mode;
412 
413 	return (0);
414 }
415 
416 /* ARGSUSED */
417 static int std_path_ping(struct scsi_device *sd, void *ctpriv)
418 {
419 	/*
420 	 * For future use
421 	 */
422 	return (1);
423 }
424 
425 /*
426  * Analyze the sense code to determine whether failover process
427  */
428 /* ARGSUSED */
429 static int
430 std_analyze_sense(struct scsi_device *sd, uint8_t *sense,
431     void *ctpriv)
432 {
433 	int rval = SCSI_SENSE_UNKNOWN;
434 
435 	uint8_t skey, asc, ascq;
436 
437 	skey = scsi_sense_key(sense);
438 	asc = scsi_sense_asc(sense);
439 	ascq = scsi_sense_ascq(sense);
440 
441 	if ((skey == KEY_UNIT_ATTENTION) &&
442 	    (asc == STD_SCSI_ASC_STATE_CHG) &&
443 	    (ascq == STD_SCSI_ASCQ_STATE_CHG_SUCC)) {
444 		rval = SCSI_SENSE_STATE_CHANGED;
445 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_analyze_sense:"
446 		    " sense_key:%x, add_code: %x, qual_code:%x"
447 		    " sense:%x\n", skey, asc, ascq, rval));
448 	} else if ((skey == KEY_NOT_READY) &&
449 	    (asc == STD_LOGICAL_UNIT_NOT_ACCESSIBLE) &&
450 	    ((ascq == STD_TGT_PORT_UNAVAILABLE) ||
451 	    (ascq == STD_TGT_PORT_STANDBY))) {
452 		rval = SCSI_SENSE_INACTIVE;
453 		VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_analyze_sense:"
454 		    " sense_key:%x, add_code: %x, qual_code:%x"
455 		    " sense:%x\n", skey, asc, ascq, rval));
456 	} else if ((skey == KEY_ILLEGAL_REQUEST) &&
457 	    (asc == STD_SCSI_ASC_INVAL_PARAM_LIST)) {
458 		rval = SCSI_SENSE_NOFAILOVER;
459 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_analyze_sense:"
460 		    " sense_key:%x, add_code: %x, qual_code:%x"
461 		    " sense:%x\n", skey, asc, ascq, rval));
462 	} else if ((skey == KEY_ILLEGAL_REQUEST) &&
463 	    (asc == STD_SCSI_ASC_INVAL_CMD_OPCODE)) {
464 		rval = SCSI_SENSE_NOFAILOVER;
465 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_analyze_sense:"
466 		    " sense_key:%x, add_code: %x, qual_code:%x"
467 		    " sense:%x\n", skey, asc, ascq, rval));
468 	} else {
469 		/*
470 		 * At this point sense data may be for power-on-reset
471 		 * UNIT ATTN hardware errors, vendor unqiue sense data etc.
472 		 * For all these cases, return SCSI_SENSE_UNKNOWN.
473 		 */
474 		VHCI_DEBUG(1, (CE_NOTE, NULL, "!Analyze sense UNKNOWN:"
475 		    " sense key:%x, ASC:%x, ASCQ:%x\n", skey, asc, ascq));
476 	}
477 
478 	return (rval);
479 }
480 
481 /* ARGSUSED */
482 static int
483 std_pathclass_next(char *cur, char **nxt, void *ctpriv)
484 {
485 	/*
486 	 * The first phase does not have a standby path so
487 	 * there will be no explicit failover - when standard tpgs.
488 	 * standard defines preferred flag then we should start
489 	 * using this as the selection mechanism - there can be
490 	 * preferred primary standby that we should fail to first and then
491 	 * nonpreferred secondary standby.
492 	 */
493 	if (cur == NULL) {
494 		*nxt = PCLASS_PRIMARY;
495 		return (0);
496 	} else if (strcmp(cur, PCLASS_PRIMARY) == 0) {
497 		*nxt = PCLASS_SECONDARY;
498 		return (0);
499 	} else if (strcmp(cur, PCLASS_SECONDARY) == 0) {
500 		return (ENOENT);
501 	} else {
502 		return (EINVAL);
503 	}
504 }
505