/**
 * mrsas_startio:           SCSI IO entry point   
 * input:                   Adapter instance soft state 
 *                          pointer to CAM Control Block
 *
 * This function is the SCSI IO entry point and it initiates IO processing. 
 * It copies the IO and depending if the IO is read/write or inquiry, it would 
 * call mrsas_build_ldio() or mrsas_build_dcdb(), respectively.  It returns
 * 0 if the command is sent to firmware successfully, otherwise it returns 1.
 */
static int32_t mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim, 
                             union ccb *ccb)
{
    struct mrsas_mpt_cmd *cmd;
    struct ccb_hdr *ccb_h = &(ccb->ccb_h);
    struct ccb_scsiio *csio = &(ccb->csio);
    MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;

    if ((csio->cdb_io.cdb_bytes[0]) == SYNCHRONIZE_CACHE){
        ccb->ccb_h.status = CAM_REQ_CMP;
        xpt_done(ccb);
        return(0);
    }

    ccb_h->status |= CAM_SIM_QUEUED;
    cmd = mrsas_get_mpt_cmd(sc);

    if (!cmd) {
        ccb_h->status |= CAM_REQUEUE_REQ;
        xpt_done(ccb);
        return(0);  
    }

    if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
        if(ccb_h->flags & CAM_DIR_IN)
            cmd->flags |= MRSAS_DIR_IN;
        if(ccb_h->flags & CAM_DIR_OUT)
            cmd->flags |= MRSAS_DIR_OUT;
    } 
    else 
        cmd->flags = MRSAS_DIR_NONE; /* no data */

/* For FreeBSD 10.0 and higher */
#if 0 /* XXX (__FreeBSD_version >= 1000000) */
/*
 *      * XXX We don't yet support physical addresses here.
 */ 
    switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
    case CAM_DATA_PADDR:
    case CAM_DATA_SG_PADDR:
         kprintf("%s: physical addresses not supported\n",
               __func__);
         mrsas_release_mpt_cmd(cmd);
         ccb_h->status = CAM_REQ_INVALID;
         ccb_h->status &= ~CAM_SIM_QUEUED;
         goto done;
    case CAM_DATA_SG:
         kprintf("%s: scatter gather is not supported\n",
               __func__);
         mrsas_release_mpt_cmd(cmd);
         ccb_h->status = CAM_REQ_INVALID;
         goto done;
	case CAM_DATA_VADDR:
         if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) {
              mrsas_release_mpt_cmd(cmd);
              ccb_h->status = CAM_REQ_TOO_BIG;
              goto done;
          }
          cmd->length = csio->dxfer_len;
          if (cmd->length) 
              cmd->data = csio->data_ptr;
        break;
    default:
        ccb->ccb_h.status = CAM_REQ_INVALID;
        goto done;
    }
#else
    if (!(ccb_h->flags & CAM_DATA_PHYS)) {  //Virtual data address
         if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
             if (csio->dxfer_len > MRSAS_MAX_IO_SIZE) {
                 mrsas_release_mpt_cmd(cmd);
                 ccb_h->status = CAM_REQ_TOO_BIG;
                 goto done;
             }
             cmd->length = csio->dxfer_len;
             if (cmd->length) 
                 cmd->data = csio->data_ptr;
         } 
         else { 
             mrsas_release_mpt_cmd(cmd);
             ccb_h->status = CAM_REQ_INVALID;
             goto done;
         }
    } 
    else { //Data addresses are physical.
         mrsas_release_mpt_cmd(cmd);
         ccb_h->status = CAM_REQ_INVALID;
         ccb_h->status &= ~CAM_SIM_QUEUED;
         goto done;
    }
#endif
    /* save ccb ptr */
    cmd->ccb_ptr = ccb;

    req_desc = mrsas_get_request_desc(sc, (cmd->index)-1);
    if (!req_desc) {
        device_printf(sc->mrsas_dev, "Cannot get request_descriptor.\n");
        return (FAIL);
    }
    memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION));
    cmd->request_desc = req_desc;

    if (ccb_h->flags & CAM_CDB_POINTER)
        bcopy(csio->cdb_io.cdb_ptr, cmd->io_request->CDB.CDB32, csio->cdb_len);
    else
        bcopy(csio->cdb_io.cdb_bytes, cmd->io_request->CDB.CDB32, csio->cdb_len);
    lockmgr(&sc->raidmap_lock, LK_EXCLUSIVE);

    if (mrsas_ldio_inq(sim, ccb)) {
        if (mrsas_build_ldio(sc, cmd, ccb)){
            device_printf(sc->mrsas_dev, "Build LDIO failed.\n");
	    lockmgr(&sc->raidmap_lock, LK_RELEASE);
            return(1);
        }    
    }
    else { 
        if (mrsas_build_dcdb(sc, cmd, ccb, sim)) {
            device_printf(sc->mrsas_dev, "Build DCDB failed.\n");
	    lockmgr(&sc->raidmap_lock, LK_RELEASE);
            return(1);
        }
    }
    lockmgr(&sc->raidmap_lock, LK_RELEASE);

    if (cmd->flags == MRSAS_DIR_IN) //from device
        cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
    else if (cmd->flags == MRSAS_DIR_OUT)  //to device
        cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;

    cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
    cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL)/4;
    cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
    cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE;

    req_desc = cmd->request_desc;
    req_desc->SCSIIO.SMID = cmd->index;

    /*
     * Start timer for IO timeout. Default timeout value is 90 second.
     */
    callout_reset(&cmd->cm_callout, (sc->mrsas_io_timeout * hz) / 1000,
        mrsas_scsiio_timeout, cmd);
    atomic_inc(&sc->fw_outstanding);

	if(atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater)
        sc->io_cmds_highwater++;

    mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high);
    return(0);

done:
    xpt_done(ccb);
    return(0);
}
Exemplo n.º 2
0
/*
 * mrsas_startio:	SCSI IO entry point
 * input:			Adapter instance soft state
 * 					pointer to CAM Control Block
 *
 * This function is the SCSI IO entry point and it initiates IO processing. It
 * copies the IO and depending if the IO is read/write or inquiry, it would
 * call mrsas_build_ldio() or mrsas_build_dcdb(), respectively.  It returns 0
 * if the command is sent to firmware successfully, otherwise it returns 1.
 */
static int32_t
mrsas_startio(struct mrsas_softc *sc, struct cam_sim *sim,
    union ccb *ccb)
{
	struct mrsas_mpt_cmd *cmd;
	struct ccb_hdr *ccb_h = &(ccb->ccb_h);
	struct ccb_scsiio *csio = &(ccb->csio);
	MRSAS_REQUEST_DESCRIPTOR_UNION *req_desc;
	u_int8_t cmd_type;

	if ((csio->cdb_io.cdb_bytes[0]) == SYNCHRONIZE_CACHE) {
		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		return (0);
	}
	ccb_h->status |= CAM_SIM_QUEUED;
	cmd = mrsas_get_mpt_cmd(sc);

	if (!cmd) {
		ccb_h->status |= CAM_REQUEUE_REQ;
		xpt_done(ccb);
		return (0);
	}
	if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		if (ccb_h->flags & CAM_DIR_IN)
			cmd->flags |= MRSAS_DIR_IN;
		if (ccb_h->flags & CAM_DIR_OUT)
			cmd->flags |= MRSAS_DIR_OUT;
	} else
		cmd->flags = MRSAS_DIR_NONE;	/* no data */

/* For FreeBSD 9.2 and higher */
#if (__FreeBSD_version >= 902001)
	/*
	 * XXX We don't yet support physical addresses here.
	 */
	switch ((ccb->ccb_h.flags & CAM_DATA_MASK)) {
	case CAM_DATA_PADDR:
	case CAM_DATA_SG_PADDR:
		device_printf(sc->mrsas_dev, "%s: physical addresses not supported\n",
		    __func__);
		mrsas_release_mpt_cmd(cmd);
		ccb_h->status = CAM_REQ_INVALID;
		ccb_h->status &= ~CAM_SIM_QUEUED;
		goto done;
	case CAM_DATA_SG:
		device_printf(sc->mrsas_dev, "%s: scatter gather is not supported\n",
		    __func__);
		mrsas_release_mpt_cmd(cmd);
		ccb_h->status = CAM_REQ_INVALID;
		goto done;
	case CAM_DATA_VADDR:
		if (csio->dxfer_len > (sc->max_num_sge * MRSAS_PAGE_SIZE)) {
			mrsas_release_mpt_cmd(cmd);
			ccb_h->status = CAM_REQ_TOO_BIG;
			goto done;
		}
		cmd->length = csio->dxfer_len;
		if (cmd->length)
			cmd->data = csio->data_ptr;
		break;
	case CAM_DATA_BIO:
		if (csio->dxfer_len > (sc->max_num_sge * MRSAS_PAGE_SIZE)) {
			mrsas_release_mpt_cmd(cmd);
			ccb_h->status = CAM_REQ_TOO_BIG;
			goto done;
		}
		cmd->length = csio->dxfer_len;
		if (cmd->length)
			cmd->data = csio->data_ptr;
		break;
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		goto done;
	}
#else
	if (!(ccb_h->flags & CAM_DATA_PHYS)) {	/* Virtual data address */
		if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
			if (csio->dxfer_len > (sc->max_num_sge * MRSAS_PAGE_SIZE)) {
				mrsas_release_mpt_cmd(cmd);
				ccb_h->status = CAM_REQ_TOO_BIG;
				goto done;
			}
			cmd->length = csio->dxfer_len;
			if (cmd->length)
				cmd->data = csio->data_ptr;
		} else {
			mrsas_release_mpt_cmd(cmd);
			ccb_h->status = CAM_REQ_INVALID;
			goto done;
		}
	} else {			/* Data addresses are physical. */
		mrsas_release_mpt_cmd(cmd);
		ccb_h->status = CAM_REQ_INVALID;
		ccb_h->status &= ~CAM_SIM_QUEUED;
		goto done;
	}
#endif
	/* save ccb ptr */
	cmd->ccb_ptr = ccb;

	req_desc = mrsas_get_request_desc(sc, (cmd->index) - 1);
	if (!req_desc) {
		device_printf(sc->mrsas_dev, "Cannot get request_descriptor.\n");
		return (FAIL);
	}
	memset(req_desc, 0, sizeof(MRSAS_REQUEST_DESCRIPTOR_UNION));
	cmd->request_desc = req_desc;

	if (ccb_h->flags & CAM_CDB_POINTER)
		bcopy(csio->cdb_io.cdb_ptr, cmd->io_request->CDB.CDB32, csio->cdb_len);
	else
		bcopy(csio->cdb_io.cdb_bytes, cmd->io_request->CDB.CDB32, csio->cdb_len);
	mtx_lock(&sc->raidmap_lock);

	/* Check for IO type READ-WRITE targeted for Logical Volume */
	cmd_type = mrsas_find_io_type(sim, ccb);
	switch (cmd_type) {
	case READ_WRITE_LDIO:
		/* Build READ-WRITE IO for Logical Volume  */
		if (mrsas_build_ldio_rw(sc, cmd, ccb)) {
			device_printf(sc->mrsas_dev, "Build RW LDIO failed.\n");
			mtx_unlock(&sc->raidmap_lock);
			return (1);
		}
		break;
	case NON_READ_WRITE_LDIO:
		/* Build NON READ-WRITE IO for Logical Volume  */
		if (mrsas_build_ldio_nonrw(sc, cmd, ccb)) {
			device_printf(sc->mrsas_dev, "Build NON-RW LDIO failed.\n");
			mtx_unlock(&sc->raidmap_lock);
			return (1);
		}
		break;
	case READ_WRITE_SYSPDIO:
	case NON_READ_WRITE_SYSPDIO:
		if (sc->secure_jbod_support &&
		    (cmd_type == NON_READ_WRITE_SYSPDIO)) {
			/* Build NON-RW IO for JBOD */
			if (mrsas_build_syspdio(sc, cmd, ccb, sim, 0)) {
				device_printf(sc->mrsas_dev,
				    "Build SYSPDIO failed.\n");
				mtx_unlock(&sc->raidmap_lock);
				return (1);
			}
		} else {
			/* Build RW IO for JBOD */
			if (mrsas_build_syspdio(sc, cmd, ccb, sim, 1)) {
				device_printf(sc->mrsas_dev,
				    "Build SYSPDIO failed.\n");
				mtx_unlock(&sc->raidmap_lock);
				return (1);
			}
		}
	}
	mtx_unlock(&sc->raidmap_lock);

	if (cmd->flags == MRSAS_DIR_IN)	/* from device */
		cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
	else if (cmd->flags == MRSAS_DIR_OUT)	/* to device */
		cmd->io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;

	cmd->io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
	cmd->io_request->SGLOffset0 = offsetof(MRSAS_RAID_SCSI_IO_REQUEST, SGL) / 4;
	cmd->io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
	cmd->io_request->SenseBufferLength = MRSAS_SCSI_SENSE_BUFFERSIZE;

	req_desc = cmd->request_desc;
	req_desc->SCSIIO.SMID = cmd->index;

	/*
	 * Start timer for IO timeout. Default timeout value is 90 second.
	 */
#if (__FreeBSD_version >= 1000510)
	callout_reset_sbt(&cmd->cm_callout, SBT_1S * 600, 0,
	    mrsas_scsiio_timeout, cmd, 0);
#else
	callout_reset(&cmd->cm_callout, (600000 * hz) / 1000,
	    mrsas_scsiio_timeout, cmd);
#endif
	mrsas_atomic_inc(&sc->fw_outstanding);

	if (mrsas_atomic_read(&sc->fw_outstanding) > sc->io_cmds_highwater)
		sc->io_cmds_highwater++;

	mrsas_fire_cmd(sc, req_desc->addr.u.low, req_desc->addr.u.high);
	return (0);

done:
	xpt_done(ccb);
	return (0);
}