예제 #1
0
/********************************************************************************
 * Handle completion of a command submitted via CAM.
 * Completion for extended cdb
 */
static void
amr_cam_complete_extcdb(struct amr_command *ac)
{
    struct amr_ext_passthrough      *aep = (struct amr_ext_passthrough *)ac->ac_data;
    struct ccb_scsiio           *csio = (struct ccb_scsiio *)ac->ac_private;
    struct scsi_inquiry_data    *inq = (struct scsi_inquiry_data *)csio->data_ptr;

    /* XXX note that we're ignoring ac->ac_status - good idea? */

    debug(1, "status 0x%x  scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status);

    /*
     * Hide disks from CAM so that they're not picked up and treated as 'normal' disks.
     *
     * If the configuration provides a mechanism to mark a disk a "not managed", we
     * could add handling for that to allow disks to be selectively visible.
     */

    if ((aep->ap_cdb[0] == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) {
	bzero(csio->data_ptr, csio->dxfer_len);
	if (aep->ap_scsi_status == 0xf0) {
	    csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
	} else {
	    csio->ccb_h.status = CAM_DEV_NOT_THERE;
	}
    } else {

	/* handle passthrough SCSI status */
	switch(aep->ap_scsi_status) {
	case 0:				/* completed OK */
	    csio->ccb_h.status = CAM_REQ_CMP;
	    break;

	case 0x02:
	    csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
	    csio->scsi_status = SCSI_STATUS_CHECK_COND;
	    bcopy(aep->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN);
	    csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
	    csio->ccb_h.status |= CAM_AUTOSNS_VALID;
	    break;

	case 0x08:
	    csio->ccb_h.status = CAM_SCSI_BUSY;
	    break;

	case 0xf0:
	case 0xf4:
	default:
	    csio->ccb_h.status = CAM_REQ_CMP_ERR;
	    break;
	}
    }
    free(aep, M_DEVBUF);
    if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
	debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " ");
    xpt_done((union ccb *)csio);
    amr_releasecmd(ac);
}
예제 #2
0
파일: amr_cam.c 프로젝트: AhmadTux/freebsd
 /**********************************************************************
 * Handle completion of a command submitted via CAM.
 */
static void
amr_cam_complete(struct amr_command *ac)
{
	struct amr_passthrough		*ap;
	struct amr_ext_passthrough	*aep;
	struct ccb_scsiio		*csio;
	struct scsi_inquiry_data	*inq;
	int				scsi_status, cdb0;

	ap = &ac->ac_ccb->ccb_pthru;
	aep = &ac->ac_ccb->ccb_epthru;
	csio = (struct ccb_scsiio *)ac->ac_private;
	inq = (struct scsi_inquiry_data *)csio->data_ptr;

	if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
		scsi_status = aep->ap_scsi_status;
	else
		scsi_status = ap->ap_scsi_status;
	debug(1, "status 0x%x  AP scsi_status 0x%x", ac->ac_status,
	    scsi_status);

	/* Make sure the status is sane */
	if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) {
		csio->ccb_h.status = CAM_REQ_CMP_ERR;
		goto out;
	}

	/*
	 * Hide disks from CAM so that they're not picked up and treated as
	 * 'normal' disks.
	 *
	 * If the configuration provides a mechanism to mark a disk a "not
	 * managed", we could add handling for that to allow disks to be
	 * selectively visible.
	 */

	/* handle passthrough SCSI status */
	switch(scsi_status) {
	case 0:	/* completed OK */
		if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
			cdb0 = aep->ap_cdb[0];
		else
			cdb0 = ap->ap_cdb[0];
		if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
			inq->device = (inq->device & 0xe0) | T_NODEVICE;
		csio->ccb_h.status = CAM_REQ_CMP;
		break;

	case 0x02:
		csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
		csio->scsi_status = SCSI_STATUS_CHECK_COND;
		if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
			bcopy(aep->ap_request_sense_area, &csio->sense_data,
			    AMR_MAX_REQ_SENSE_LEN);
		else
			bcopy(ap->ap_request_sense_area, &csio->sense_data,
			    AMR_MAX_REQ_SENSE_LEN);
		csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
		csio->ccb_h.status |= CAM_AUTOSNS_VALID;
		break;

	case 0x08:
		csio->ccb_h.status = CAM_SCSI_BUSY;
		break;

	case 0xf0:
	case 0xf4:
	default:
		/*
		 * Non-zero LUNs are already filtered, so there's no need
		 * to return CAM_DEV_NOT_THERE.
		 */
		csio->ccb_h.status = CAM_SEL_TIMEOUT;
		break;
	}

out:
	if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
		debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr,
		    " ");

	mtx_lock(&ac->ac_sc->amr_list_lock);
	xpt_done((union ccb *)csio);
	amr_releasecmd(ac);
	mtx_unlock(&ac->ac_sc->amr_list_lock);
}
예제 #3
0
파일: amr_cam.c 프로젝트: AhmadTux/freebsd
/***********************************************************************
 * Convert a CAM CCB off the top of the CCB queue to a passthrough SCSI
 * command.
 */
static int
amr_cam_command(struct amr_softc *sc, struct amr_command **acp)
{
	struct amr_command		*ac;
	struct amr_passthrough		*ap;
	struct amr_ext_passthrough	*aep;
	struct ccb_scsiio		*csio;
	int				bus, target, error;

	error = 0;
	ac = NULL;
	ap = NULL;
	aep = NULL;

	/* check to see if there is a ccb for us to work with */
	if ((csio = (struct ccb_scsiio *)amr_dequeue_ccb(sc)) == NULL)
	goto out;

	/* get bus/target, XXX validate against protected devices? */
	bus = csio->ccb_h.sim_priv.entries[0].field;
	target = csio->ccb_h.target_id;

	/*
	 * Build a passthrough command.
	 */

	/* construct command */
	if ((ac = amr_alloccmd(sc)) == NULL) {
		error = ENOMEM;
		goto out;
	}

	/* construct passthrough */
	if (sc->support_ext_cdb ) {
		aep = &ac->ac_ccb->ccb_epthru;
		aep->ap_timeout = 2;
		aep->ap_ars = 1;
		aep->ap_request_sense_length = 14;
		aep->ap_islogical = 0;
		aep->ap_channel = bus;
		aep->ap_scsi_id = target;
		aep->ap_logical_drive_no = csio->ccb_h.target_lun;
		aep->ap_cdb_length = csio->cdb_len;
		aep->ap_data_transfer_length = csio->dxfer_len;
		if (csio->ccb_h.flags & CAM_CDB_POINTER) {
			bcopy(csio->cdb_io.cdb_ptr, aep->ap_cdb, csio->cdb_len);
		} else {
			bcopy(csio->cdb_io.cdb_bytes, aep->ap_cdb,
			    csio->cdb_len);
		}
		/*
		 * we leave the data s/g list and s/g count to the map routine
		 * later
		 */

		debug(2, " COMMAND %x/%d+%d to %d:%d:%d", aep->ap_cdb[0],
		    aep->ap_cdb_length, csio->dxfer_len, aep->ap_channel,
		    aep->ap_scsi_id, aep->ap_logical_drive_no);

	} else {
		ap = &ac->ac_ccb->ccb_pthru;
		ap->ap_timeout = 0;
		ap->ap_ars = 1;
		ap->ap_request_sense_length = 14;
		ap->ap_islogical = 0;
		ap->ap_channel = bus;
		ap->ap_scsi_id = target;
		ap->ap_logical_drive_no = csio->ccb_h.target_lun;
		ap->ap_cdb_length = csio->cdb_len;
		ap->ap_data_transfer_length = csio->dxfer_len;
		if (csio->ccb_h.flags & CAM_CDB_POINTER) {
			bcopy(csio->cdb_io.cdb_ptr, ap->ap_cdb, csio->cdb_len);
		} else {
			bcopy(csio->cdb_io.cdb_bytes, ap->ap_cdb,
			    csio->cdb_len);
		}
		/*
		 * we leave the data s/g list and s/g count to the map routine
		 * later
		 */

		debug(2, " COMMAND %x/%d+%d to %d:%d:%d", ap->ap_cdb[0],
		    ap->ap_cdb_length, csio->dxfer_len, ap->ap_channel,
		    ap->ap_scsi_id, ap->ap_logical_drive_no);
	}

	ac->ac_flags |= AMR_CMD_CCB;

	ac->ac_data = csio->data_ptr;
	ac->ac_length = csio->dxfer_len;
	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
		ac->ac_flags |= AMR_CMD_DATAIN;
	if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
		ac->ac_flags |= AMR_CMD_DATAOUT;

	ac->ac_private = csio;
	ac->ac_complete = amr_cam_complete;
	if ( sc->support_ext_cdb ) {
		ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS;
	} else {
		ac->ac_mailbox.mb_command = AMR_CMD_PASS;
	}

out:
	if (error != 0) {
		if (ac != NULL)
			amr_releasecmd(ac);
		if (csio != NULL)
			/* put it back and try again later */
			amr_requeue_ccb(sc, (union ccb *)csio);
	}
	*acp = ac;
	return(error);
}