static DEF_SCSI_QCMD()

in megaraid/megaraid_mbox.c [1466:1845]


static DEF_SCSI_QCMD(megaraid_queue_command)

/**
 * megaraid_mbox_build_cmd - transform the mid-layer scsi commands
 * @adapter	: controller's soft state
 * @scp		: mid-layer scsi command pointer
 * @busy	: set if request could not be completed because of lack of
 *		resources
 *
 * Transform the mid-layer scsi command to megaraid firmware lingua.
 * Convert the command issued by mid-layer to format understood by megaraid
 * firmware. We also complete certain commands without sending them to firmware.
 */
static scb_t *
megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
{
	mraid_device_t		*rdev = ADAP2RAIDDEV(adapter);
	int			channel;
	int			target;
	int			islogical;
	mbox_ccb_t		*ccb;
	mraid_passthru_t	*pthru;
	mbox64_t		*mbox64;
	mbox_t			*mbox;
	scb_t			*scb;
	char			skip[] = "skipping";
	char			scan[] = "scanning";
	char			*ss;


	/*
	 * Get the appropriate device map for the device this command is
	 * intended for
	 */
	MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical);

	/*
	 * Logical drive commands
	 */
	if (islogical) {
		switch (scp->cmnd[0]) {
		case TEST_UNIT_READY:
			/*
			 * Do we support clustering and is the support enabled
			 * If no, return success always
			 */
			if (!adapter->ha) {
				scp->result = (DID_OK << 16);
				return NULL;
			}

			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
				scp->result = (DID_ERROR << 16);
				*busy = 1;
				return NULL;
			}

			scb->dma_direction	= scp->sc_data_direction;
			scb->dev_channel	= 0xFF;
			scb->dev_target		= target;
			ccb			= (mbox_ccb_t *)scb->ccb;

			/*
			 * The command id will be provided by the command
			 * issuance routine
			 */
			ccb->raw_mbox[0]	= CLUSTER_CMD;
			ccb->raw_mbox[2]	= RESERVATION_STATUS;
			ccb->raw_mbox[3]	= target;

			return scb;

		case MODE_SENSE:
		{
			struct scatterlist	*sgl;
			caddr_t			vaddr;

			sgl = scsi_sglist(scp);
			if (sg_page(sgl)) {
				vaddr = (caddr_t) sg_virt(&sgl[0]);

				memset(vaddr, 0, scp->cmnd[4]);
			}
			else {
				con_log(CL_ANN, (KERN_WARNING
						 "megaraid mailbox: invalid sg:%d\n",
						 __LINE__));
			}
		}
		scp->result = (DID_OK << 16);
		return NULL;

		case INQUIRY:
			/*
			 * Display the channel scan for logical drives
			 * Do not display scan for a channel if already done.
			 */
			if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {

				con_log(CL_ANN, (KERN_INFO
					"scsi[%d]: scanning scsi channel %d",
					adapter->host->host_no,
					SCP2CHANNEL(scp)));

				con_log(CL_ANN, (
					" [virtual] for logical drives\n"));

				rdev->last_disp |= (1L << SCP2CHANNEL(scp));
			}

			if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
				scsi_build_sense(scp, 0, ILLEGAL_REQUEST,
						 MEGA_INVALID_FIELD_IN_CDB, 0);
				return NULL;
			}

			fallthrough;

		case READ_CAPACITY:
			/*
			 * Do not allow LUN > 0 for logical drives and
			 * requests for more than 40 logical drives
			 */
			if (SCP2LUN(scp)) {
				scp->result = (DID_BAD_TARGET << 16);
				return NULL;
			}
			if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) {
				scp->result = (DID_BAD_TARGET << 16);
				return NULL;
			}


			/* Allocate a SCB and initialize passthru */
			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
				scp->result = (DID_ERROR << 16);
				*busy = 1;
				return NULL;
			}

			ccb			= (mbox_ccb_t *)scb->ccb;
			scb->dev_channel	= 0xFF;
			scb->dev_target		= target;
			pthru			= ccb->pthru;
			mbox			= ccb->mbox;
			mbox64			= ccb->mbox64;

			pthru->timeout		= 0;
			pthru->ars		= 1;
			pthru->reqsenselen	= 14;
			pthru->islogical	= 1;
			pthru->logdrv		= target;
			pthru->cdblen		= scp->cmd_len;
			memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);

			mbox->cmd		= MBOXCMD_PASSTHRU64;
			scb->dma_direction	= scp->sc_data_direction;

			pthru->dataxferlen	= scsi_bufflen(scp);
			pthru->dataxferaddr	= ccb->sgl_dma_h;
			pthru->numsge		= megaraid_mbox_mksgl(adapter,
							scb);

			mbox->xferaddr		= 0xFFFFFFFF;
			mbox64->xferaddr_lo	= (uint32_t )ccb->pthru_dma_h;
			mbox64->xferaddr_hi	= 0;

			return scb;

		case READ_6:
		case WRITE_6:
		case READ_10:
		case WRITE_10:
		case READ_12:
		case WRITE_12:

			/*
			 * Allocate a SCB and initialize mailbox
			 */
			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
				scp->result = (DID_ERROR << 16);
				*busy = 1;
				return NULL;
			}
			ccb			= (mbox_ccb_t *)scb->ccb;
			scb->dev_channel	= 0xFF;
			scb->dev_target		= target;
			mbox			= ccb->mbox;
			mbox64			= ccb->mbox64;
			mbox->logdrv		= target;

			/*
			 * A little HACK: 2nd bit is zero for all scsi read
			 * commands and is set for all scsi write commands
			 */
			mbox->cmd = (scp->cmnd[0] & 0x02) ?  MBOXCMD_LWRITE64:
					MBOXCMD_LREAD64 ;

			/*
			 * 6-byte READ(0x08) or WRITE(0x0A) cdb
			 */
			if (scp->cmd_len == 6) {
				mbox->numsectors = (uint32_t)scp->cmnd[4];
				mbox->lba =
					((uint32_t)scp->cmnd[1] << 16)	|
					((uint32_t)scp->cmnd[2] << 8)	|
					(uint32_t)scp->cmnd[3];

				mbox->lba &= 0x1FFFFF;
			}

			/*
			 * 10-byte READ(0x28) or WRITE(0x2A) cdb
			 */
			else if (scp->cmd_len == 10) {
				mbox->numsectors =
					(uint32_t)scp->cmnd[8] |
					((uint32_t)scp->cmnd[7] << 8);
				mbox->lba =
					((uint32_t)scp->cmnd[2] << 24) |
					((uint32_t)scp->cmnd[3] << 16) |
					((uint32_t)scp->cmnd[4] << 8) |
					(uint32_t)scp->cmnd[5];
			}

			/*
			 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
			 */
			else if (scp->cmd_len == 12) {
				mbox->lba =
					((uint32_t)scp->cmnd[2] << 24) |
					((uint32_t)scp->cmnd[3] << 16) |
					((uint32_t)scp->cmnd[4] << 8) |
					(uint32_t)scp->cmnd[5];

				mbox->numsectors =
					((uint32_t)scp->cmnd[6] << 24) |
					((uint32_t)scp->cmnd[7] << 16) |
					((uint32_t)scp->cmnd[8] << 8) |
					(uint32_t)scp->cmnd[9];
			}
			else {
				con_log(CL_ANN, (KERN_WARNING
					"megaraid: unsupported CDB length\n"));

				megaraid_dealloc_scb(adapter, scb);

				scp->result = (DID_ERROR << 16);
				return NULL;
			}

			scb->dma_direction = scp->sc_data_direction;

			// Calculate Scatter-Gather info
			mbox64->xferaddr_lo	= (uint32_t )ccb->sgl_dma_h;
			mbox->numsge		= megaraid_mbox_mksgl(adapter,
							scb);
			mbox->xferaddr		= 0xFFFFFFFF;
			mbox64->xferaddr_hi	= 0;

			return scb;

		case RESERVE:
		case RELEASE:
			/*
			 * Do we support clustering and is the support enabled
			 */
			if (!adapter->ha) {
				scp->result = (DID_BAD_TARGET << 16);
				return NULL;
			}

			/*
			 * Allocate a SCB and initialize mailbox
			 */
			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
				scp->result = (DID_ERROR << 16);
				*busy = 1;
				return NULL;
			}

			ccb			= (mbox_ccb_t *)scb->ccb;
			scb->dev_channel	= 0xFF;
			scb->dev_target		= target;
			ccb->raw_mbox[0]	= CLUSTER_CMD;
			ccb->raw_mbox[2]	=  (scp->cmnd[0] == RESERVE) ?
						RESERVE_LD : RELEASE_LD;

			ccb->raw_mbox[3]	= target;
			scb->dma_direction	= scp->sc_data_direction;

			return scb;

		default:
			scp->result = (DID_BAD_TARGET << 16);
			return NULL;
		}
	}
	else { // Passthru device commands

		// Do not allow access to target id > 15 or LUN > 7
		if (target > 15 || SCP2LUN(scp) > 7) {
			scp->result = (DID_BAD_TARGET << 16);
			return NULL;
		}

		// if fast load option was set and scan for last device is
		// over, reset the fast_load flag so that during a possible
		// next scan, devices can be made available
		if (rdev->fast_load && (target == 15) &&
			(SCP2CHANNEL(scp) == adapter->max_channel -1)) {

			con_log(CL_ANN, (KERN_INFO
			"megaraid[%d]: physical device scan re-enabled\n",
				adapter->host->host_no));
			rdev->fast_load = 0;
		}

		/*
		 * Display the channel scan for physical devices
		 */
		if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {

			ss = rdev->fast_load ? skip : scan;

			con_log(CL_ANN, (KERN_INFO
				"scsi[%d]: %s scsi channel %d [Phy %d]",
				adapter->host->host_no, ss, SCP2CHANNEL(scp),
				channel));

			con_log(CL_ANN, (
				" for non-raid devices\n"));

			rdev->last_disp |= (1L << SCP2CHANNEL(scp));
		}

		// disable channel sweep if fast load option given
		if (rdev->fast_load) {
			scp->result = (DID_BAD_TARGET << 16);
			return NULL;
		}

		// Allocate a SCB and initialize passthru
		if (!(scb = megaraid_alloc_scb(adapter, scp))) {
			scp->result = (DID_ERROR << 16);
			*busy = 1;
			return NULL;
		}

		ccb			= (mbox_ccb_t *)scb->ccb;
		scb->dev_channel	= channel;
		scb->dev_target		= target;
		scb->dma_direction	= scp->sc_data_direction;
		mbox			= ccb->mbox;
		mbox64			= ccb->mbox64;

		// Does this firmware support extended CDBs
		if (adapter->max_cdb_sz == 16) {
			mbox->cmd		= MBOXCMD_EXTPTHRU;

			megaraid_mbox_prepare_epthru(adapter, scb, scp);

			mbox64->xferaddr_lo	= (uint32_t)ccb->epthru_dma_h;
			mbox64->xferaddr_hi	= 0;
			mbox->xferaddr		= 0xFFFFFFFF;
		}
		else {
			mbox->cmd = MBOXCMD_PASSTHRU64;

			megaraid_mbox_prepare_pthru(adapter, scb, scp);

			mbox64->xferaddr_lo	= (uint32_t)ccb->pthru_dma_h;
			mbox64->xferaddr_hi	= 0;
			mbox->xferaddr		= 0xFFFFFFFF;
		}
		return scb;
	}

	// NOT REACHED
}