/* ARGSUSED */ static int std_analyze_sense(struct scsi_device *sd, uint8_t *sense, void *ctpriv) { int rval = SCSI_SENSE_UNKNOWN; uint8_t skey, asc, ascq; skey = scsi_sense_key(sense); asc = scsi_sense_asc(sense); ascq = scsi_sense_ascq(sense); if ((skey == KEY_UNIT_ATTENTION) && (asc == STD_SCSI_ASC_STATE_CHG) && (ascq == STD_SCSI_ASCQ_STATE_CHG_SUCC)) { rval = SCSI_SENSE_STATE_CHANGED; VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_analyze_sense:" " sense_key:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, rval)); } else if ((skey == KEY_NOT_READY) && (asc == STD_LOGICAL_UNIT_NOT_ACCESSIBLE) && ((ascq == STD_TGT_PORT_UNAVAILABLE) || (ascq == STD_TGT_PORT_STANDBY))) { rval = SCSI_SENSE_INACTIVE; VHCI_DEBUG(4, (CE_NOTE, NULL, "!std_analyze_sense:" " sense_key:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, rval)); } else if ((skey == KEY_ILLEGAL_REQUEST) && (asc == STD_SCSI_ASC_INVAL_PARAM_LIST)) { rval = SCSI_SENSE_NOFAILOVER; VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_analyze_sense:" " sense_key:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, rval)); } else if ((skey == KEY_ILLEGAL_REQUEST) && (asc == STD_SCSI_ASC_INVAL_CMD_OPCODE)) { rval = SCSI_SENSE_NOFAILOVER; VHCI_DEBUG(1, (CE_NOTE, NULL, "!std_analyze_sense:" " sense_key:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, rval)); } else { /* * At this point sense data may be for power-on-reset * UNIT ATTN hardware errors, vendor unqiue sense data etc. * For all these cases, return SCSI_SENSE_UNKNOWN. */ VHCI_DEBUG(1, (CE_NOTE, NULL, "!Analyze sense UNKNOWN:" " sense key:%x, ASC:%x, ASCQ:%x\n", skey, asc, ascq)); } return (rval); }
int vhci_tpgs_set_target_groups(struct scsi_address *ap, int set_state, int tpg_id) { struct scsi_pkt *pkt; struct buf *bp; int len, rval, ss = SCSI_SENSE_UNKNOWN; char *bufp; uint8_t *sns, skey, asc, ascq; len = 8; bp = getrbuf(KM_NOSLEEP); if (bp == NULL) { VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: " " failed getrbuf")); return (1); } bufp = kmem_zalloc(len, KM_NOSLEEP); if (bufp == NULL) { VHCI_DEBUG(1, (CE_WARN, NULL, "!vhci_tpgs_set_target_groups: " "request packet allocation for %d failed....", len)); freerbuf(bp); return (1); } bp->b_un.b_addr = bufp; bp->b_flags = B_WRITE; bp->b_bcount = len; bp->b_resid = 0; bufp[4] = (0x0f & set_state); bufp[6] = (0xff00 & tpg_id) >> 8; bufp[7] = (0x00ff & tpg_id); pkt = scsi_init_pkt(ap, NULL, bp, CDB_GROUP5, sizeof (struct scsi_arq_status), 0, 0, NULL, NULL); if (pkt == NULL) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups: scsi_init_pkt error\n")); freerbuf(bp); kmem_free((void *)bufp, len); return (1); } /* * Sends 1 TPG descriptor only. Hence Parameter list length pkt_cdbp[9] * is set to 8 bytes - Refer SPC3 for details. */ pkt->pkt_cdbp[0] = SCMD_MAINTENANCE_OUT; pkt->pkt_cdbp[1] = SSVC_ACTION_SET_TARGET_PORT_GROUPS; pkt->pkt_cdbp[9] = 8; pkt->pkt_time = 90; VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups: sending set target port group:" " cdb[0/1/6/7/8/9]: %x/%x/%x/%x/%x/%x\n", pkt->pkt_cdbp[0], pkt->pkt_cdbp[1], pkt->pkt_cdbp[6], pkt->pkt_cdbp[7], pkt->pkt_cdbp[8], pkt->pkt_cdbp[9])); #ifdef DEBUG print_buf(bufp, len); #endif rval = vhci_do_scsi_cmd(pkt); if (rval == 0) { VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:" " vhci_do_scsi_cmd failed\n")); freerbuf(bp); kmem_free((void *)bufp, len); scsi_destroy_pkt(pkt); return (-1); } else if ((pkt->pkt_reason == CMD_CMPLT) && (SCBP_C(pkt) == STATUS_CHECK) && (pkt->pkt_state & STATE_ARQ_DONE)) { sns = (uint8_t *) &(((struct scsi_arq_status *)(uintptr_t) (pkt->pkt_scbp))->sts_sensedata); skey = scsi_sense_key(sns); asc = scsi_sense_asc(sns); ascq = scsi_sense_ascq(sns); if ((skey == KEY_UNIT_ATTENTION) && (asc == STD_SCSI_ASC_STATE_CHG) && (ascq == STD_SCSI_ASCQ_STATE_CHG_SUCC)) { ss = SCSI_SENSE_STATE_CHANGED; VHCI_DEBUG(4, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:" " sense:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, ss)); } else if ((skey == KEY_ILLEGAL_REQUEST) && (asc == STD_SCSI_ASC_INVAL_PARAM_LIST)) { ss = SCSI_SENSE_NOFAILOVER; VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:" " sense:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, ss)); } else if ((skey == KEY_ILLEGAL_REQUEST) && (asc == STD_SCSI_ASC_INVAL_CMD_OPCODE)) { ss = SCSI_SENSE_NOFAILOVER; VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups:" " sense_key:%x, add_code: %x, qual_code:%x" " sense:%x\n", skey, asc, ascq, rval)); } else { /* * At this point sns data may be for power-on-reset * UNIT ATTN hardware errors, vendor unqiue sense etc. * For all these cases, sense is unknown. */ ss = SCSI_SENSE_NOFAILOVER; VHCI_DEBUG(1, (CE_NOTE, NULL, "!vhci_tpgs_set_target_groups: " " sense UNKNOWN: sense key:%x, ASC:%x, ASCQ:%x\n", skey, asc, ascq)); } if (ss == SCSI_SENSE_STATE_CHANGED) { freerbuf(bp); kmem_free((void *)bufp, len); scsi_destroy_pkt(pkt); return (0); } } else if ((pkt->pkt_reason == CMD_CMPLT) && (SCBP_C(pkt) == STATUS_GOOD)) { freerbuf(bp); kmem_free((void *)bufp, len); scsi_destroy_pkt(pkt); return (0); } freerbuf(bp); kmem_free((void *)bufp, len); scsi_destroy_pkt(pkt); return (1); }
/* * Process the packet reason of CMD_PKT_CMPLT - return 0 if no * retry and 1 if a retry should be done */ static int std_process_cmplt_pkt(struct scsi_device *sd, struct scsi_pkt *pkt, int *retry_cnt, int *retval) { *retval = 1; /* fail */ switch (SCBP_C(pkt)) { case STATUS_GOOD: *retval = 0; break; case STATUS_CHECK: if (pkt->pkt_state & STATE_ARQ_DONE) { uint8_t *sns, skey, asc, ascq; sns = (uint8_t *) &(((struct scsi_arq_status *)(uintptr_t) (pkt->pkt_scbp))->sts_sensedata); skey = scsi_sense_key(sns); asc = scsi_sense_asc(sns); ascq = scsi_sense_ascq(sns); if (skey == KEY_UNIT_ATTENTION) { /* * tpgs access state changed */ if (asc == STD_SCSI_ASC_STATE_CHG && ascq == STD_SCSI_ASCQ_STATE_CHG_SUCC) { /* XXX: update path info? */ cmn_err(CE_WARN, "!Device failover" " state change"); } return (1); } else if (skey == KEY_NOT_READY) { if (asc == STD_LOGICAL_UNIT_NOT_ACCESSIBLE && ascq == STD_TGT_PORT_STANDBY) { /* * Don't retry on the path * which is indicated as * standby, return failure. */ return (0); } else if ((*retry_cnt)++ >= STD_FO_MAX_RETRIES) { cmn_err(CE_WARN, "!Device failover failed: " "timed out waiting for " "path to become active"); return (0); } VHCI_DEBUG(6, (CE_NOTE, NULL, "!(sd:%p)lun becoming active...\n", (void *)sd)); drv_usecwait(STD_FO_RETRY_DELAY); return (1); } cmn_err(CE_NOTE, "!Failover failed;" " sense key:%x, ASC: %x, " "ASCQ:%x", skey, asc, ascq); return (0); } VHCI_DEBUG(4, (CE_WARN, NULL, "!(sd:%p):" " status returned CHECK during std" " path activation", (void *)sd)); return (0); case STATUS_QFULL: VHCI_DEBUG(6, (CE_NOTE, NULL, "QFULL " "status returned QFULL during std " "path activation for %p\n", (void *)sd)); drv_usecwait(5000); return (1); case STATUS_BUSY: VHCI_DEBUG(6, (CE_NOTE, NULL, "BUSY " "status returned BUSY during std " "path activation for %p\n", (void *)sd)); drv_usecwait(5000); return (1); default: VHCI_DEBUG(4, (CE_WARN, NULL, "!(sd:%p) Bad status returned during std " "activation (pkt %p, status %x)", (void *)sd, (void *)pkt, SCBP_C(pkt))); return (0); } return (0); }