Ejemplo n.º 1
0
/* 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);
}
Ejemplo n.º 3
0
/*
 * 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);
}