Exemple #1
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);
}
Exemple #2
0
/*
 * mrsas_build_dcdb:	Builds an DCDB command
 * input:				Adapter instance soft state
 * 						Pointer to command packet
 * 						Pointer to CCB
 *
 * This function builds the DCDB inquiry command.  It returns 0 if the command
 * is built successfully, otherwise it returns a 1.
 */
int
mrsas_build_dcdb(struct mrsas_softc *sc, struct mrsas_mpt_cmd *cmd,
    union ccb *ccb, struct cam_sim *sim)
{
	struct ccb_hdr *ccb_h = &(ccb->ccb_h);
	u_int32_t device_id;
	MR_DRV_RAID_MAP_ALL *map_ptr;
	MRSAS_RAID_SCSI_IO_REQUEST *io_request;

	io_request = cmd->io_request;
	device_id = ccb_h->target_id;
	map_ptr = sc->ld_drv_map[(sc->map_id & 1)];

	/*
         * Check if this is RW for system PD or
         * it's a NON RW for sys PD and there is NO secure jbod FW support
         */
	if (cam_sim_bus(sim) == 1 &&
	    sc->pd_list[device_id].driveState == MR_PD_STATE_SYSTEM) {

		io_request->DevHandle =
		    map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
		io_request->RaidContext.RAIDFlags =
		    MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD <<
		    MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
		cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
		cmd->request_desc->SCSIIO.MSIxIndex =
		    sc->msix_vectors ? smp_processor_id() % sc->msix_vectors : 0;

		if (sc->secure_jbod_support && (mrsas_find_io_type(sim, ccb) == NON_READ_WRITE_SYSPDIO)) {
			/* system pd firmware path */
			io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST;
			cmd->request_desc->SCSIIO.RequestFlags =
			    (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
		} else {
			/* system pd fast path */
			io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
			io_request->RaidContext.timeoutValue = map_ptr->raidMap.fpPdIoTimeoutSec;
			io_request->RaidContext.regLockFlags = 0;
			io_request->RaidContext.regLockRowLBA = 0;
			io_request->RaidContext.regLockLength = 0;

			cmd->request_desc->SCSIIO.RequestFlags =
			    (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
			    MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);

			/*
			 * NOTE - For system pd RW cmds only IoFlags will be FAST_PATH
			 * Because the NON RW cmds will now go via FW Queue
			 * and not the Exception queue
			 */
			if ((sc->device_id == MRSAS_INVADER) || (sc->device_id == MRSAS_FURY))
				io_request->IoFlags |= MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
		}
	} else {
		/* FW path for SysPD or LD Non-RW (SCSI management commands) */
		io_request->Function = MRSAS_MPI2_FUNCTION_LD_IO_REQUEST;
		io_request->DevHandle = device_id;
		cmd->request_desc->SCSIIO.RequestFlags =
		    (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
		    MRSAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
	}

	io_request->RaidContext.VirtualDiskTgtId = device_id;
	io_request->LUN[1] = ccb_h->target_lun & 0xF;
	io_request->DataLength = cmd->length;

	if (mrsas_map_request(sc, cmd, ccb) == SUCCESS) {
		if (cmd->sge_count > sc->max_num_sge) {
			device_printf(sc->mrsas_dev, "Error: sge_count (0x%x) exceeds"
			    "max (0x%x) allowed\n", cmd->sge_count, sc->max_num_sge);
			return (1);
		}
		io_request->RaidContext.numSGE = cmd->sge_count;
	} else {
		device_printf(sc->mrsas_dev, "Data map/load failed.\n");
		return (1);
	}
	return (0);
}