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