Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb4f66be authored by Ed Lin's avatar Ed Lin Committed by James Bottomley
Browse files

[SCSI] stex: add new device (id 0x8650) support



A new device (id 0x8650, nickname 'yosemite') support is added.
It's basically the same, except for following items:
- mapping of id and lun by firmware
- special handling for some commands in interrupt routine
- change of internal copy function for these special commands
- different reset handling code
- different shutdown notification command

Signed-off-by: default avatarEd Lin <ed.lin@promise.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent f903d7b7
Loading
Loading
Loading
Loading
+164 −30
Original line number Original line Diff line number Diff line
@@ -11,7 +11,7 @@
 *	Written By:
 *	Written By:
 *		Ed Lin <promise_linux@promise.com>
 *		Ed Lin <promise_linux@promise.com>
 *
 *
 *	Version: 2.9.0.13
 *	Version: 3.0.0.1
 *
 *
 */
 */


@@ -37,11 +37,11 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_tcq.h>


#define DRV_NAME "stex"
#define DRV_NAME "stex"
#define ST_DRIVER_VERSION "2.9.0.13"
#define ST_DRIVER_VERSION "3.0.0.1"
#define ST_VER_MAJOR 		2
#define ST_VER_MAJOR 		3
#define ST_VER_MINOR 		9
#define ST_VER_MINOR 		0
#define ST_OEM 			0
#define ST_OEM 			0
#define ST_BUILD_VER 		13
#define ST_BUILD_VER 		1


enum {
enum {
	/* MU register offset */
	/* MU register offset */
@@ -120,12 +120,18 @@ enum {


	st_shasta				= 0,
	st_shasta				= 0,
	st_vsc					= 1,
	st_vsc					= 1,
	st_yosemite				= 2,


	PASSTHRU_REQ_TYPE			= 0x00000001,
	PASSTHRU_REQ_TYPE			= 0x00000001,
	PASSTHRU_REQ_NO_WAKEUP			= 0x00000100,
	PASSTHRU_REQ_NO_WAKEUP			= 0x00000100,
	ST_INTERNAL_TIMEOUT			= 30,
	ST_INTERNAL_TIMEOUT			= 30,


	ST_TO_CMD				= 0,
	ST_FROM_CMD				= 1,

	/* vendor specific commands of Promise */
	/* vendor specific commands of Promise */
	MGT_CMD					= 0xd8,
	SINBAND_MGT_CMD				= 0xd9,
	ARRAY_CMD				= 0xe0,
	ARRAY_CMD				= 0xe0,
	CONTROLLER_CMD				= 0xe1,
	CONTROLLER_CMD				= 0xe1,
	DEBUGGING_CMD				= 0xe2,
	DEBUGGING_CMD				= 0xe2,
@@ -133,14 +139,48 @@ enum {


	PASSTHRU_GET_ADAPTER			= 0x05,
	PASSTHRU_GET_ADAPTER			= 0x05,
	PASSTHRU_GET_DRVVER			= 0x10,
	PASSTHRU_GET_DRVVER			= 0x10,

	CTLR_CONFIG_CMD				= 0x03,
	CTLR_SHUTDOWN				= 0x0d,

	CTLR_POWER_STATE_CHANGE			= 0x0e,
	CTLR_POWER_STATE_CHANGE			= 0x0e,
	CTLR_POWER_SAVING			= 0x01,
	CTLR_POWER_SAVING			= 0x01,


	PASSTHRU_SIGNATURE			= 0x4e415041,
	PASSTHRU_SIGNATURE			= 0x4e415041,
	MGT_CMD_SIGNATURE			= 0xba,


	INQUIRY_EVPD				= 0x01,
	INQUIRY_EVPD				= 0x01,
};
};


/* SCSI inquiry data */
typedef struct st_inq {
	u8 DeviceType			:5;
	u8 DeviceTypeQualifier		:3;
	u8 DeviceTypeModifier		:7;
	u8 RemovableMedia		:1;
	u8 Versions;
	u8 ResponseDataFormat		:4;
	u8 HiSupport			:1;
	u8 NormACA			:1;
	u8 ReservedBit			:1;
	u8 AERC				:1;
	u8 AdditionalLength;
	u8 Reserved[2];
	u8 SoftReset			:1;
	u8 CommandQueue			:1;
	u8 Reserved2			:1;
	u8 LinkedCommands		:1;
	u8 Synchronous			:1;
	u8 Wide16Bit			:1;
	u8 Wide32Bit			:1;
	u8 RelativeAddressing		:1;
	u8 VendorId[8];
	u8 ProductId[16];
	u8 ProductRevisionLevel[4];
	u8 VendorSpecific[20];
	u8 Reserved3[40];
} ST_INQ;

struct st_sgitem {
struct st_sgitem {
	u8 ctrl;	/* SG_CF_xxx */
	u8 ctrl;	/* SG_CF_xxx */
	u8 reserved[3];
	u8 reserved[3];
@@ -242,7 +282,8 @@ struct st_drvver {
#define MU_REQ_BUFFER_SIZE	(MU_REQ_COUNT * sizeof(struct req_msg))
#define MU_REQ_BUFFER_SIZE	(MU_REQ_COUNT * sizeof(struct req_msg))
#define MU_STATUS_BUFFER_SIZE	(MU_STATUS_COUNT * sizeof(struct status_msg))
#define MU_STATUS_BUFFER_SIZE	(MU_STATUS_COUNT * sizeof(struct status_msg))
#define MU_BUFFER_SIZE		(MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
#define MU_BUFFER_SIZE		(MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
#define STEX_BUFFER_SIZE	(MU_BUFFER_SIZE + sizeof(struct st_frame))
#define STEX_EXTRA_SIZE		max(sizeof(struct st_frame), sizeof(ST_INQ))
#define STEX_BUFFER_SIZE	(MU_BUFFER_SIZE + STEX_EXTRA_SIZE)


struct st_ccb {
struct st_ccb {
	struct req_msg *req;
	struct req_msg *req;
@@ -403,7 +444,7 @@ static int stex_map_sg(struct st_hba *hba,
}
}


static void stex_internal_copy(struct scsi_cmnd *cmd,
static void stex_internal_copy(struct scsi_cmnd *cmd,
	const void *src, size_t *count, int sg_count)
	const void *src, size_t *count, int sg_count, int direction)
{
{
	size_t lcount;
	size_t lcount;
	size_t len;
	size_t len;
@@ -427,7 +468,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
		} else
		} else
			d = cmd->request_buffer;
			d = cmd->request_buffer;


		if (direction == ST_TO_CMD)
			memcpy(d, s, len);
			memcpy(d, s, len);
		else
			memcpy(s, d, len);


		lcount -= len;
		lcount -= len;
		if (cmd->use_sg)
		if (cmd->use_sg)
@@ -449,7 +493,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd,
			return 0;
			return 0;
	}
	}


	stex_internal_copy(cmd, src, &cp_len, n_elem);
	stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);


	if (cmd->use_sg)
	if (cmd->use_sg)
		pci_unmap_sg(hba->pdev, cmd->request_buffer,
		pci_unmap_sg(hba->pdev, cmd->request_buffer,
@@ -480,7 +524,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
	p->subid =
	p->subid =
		hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
		hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;


	stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
	stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
}
}


static void
static void
@@ -594,8 +638,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
		return SCSI_MLQUEUE_HOST_BUSY;
		return SCSI_MLQUEUE_HOST_BUSY;


	req = stex_alloc_req(hba);
	req = stex_alloc_req(hba);

	if (hba->cardtype == st_yosemite) {
		req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
		req->target = 0;
	} else {
		req->lun = lun;
		req->lun = lun;
		req->target = id;
		req->target = id;
	}


	/* cdb */
	/* cdb */
	memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
	memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
@@ -679,7 +729,51 @@ static void stex_copy_data(struct st_ccb *ccb,


	if (ccb->cmd == NULL)
	if (ccb->cmd == NULL)
		return;
		return;
	stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
	stex_internal_copy(ccb->cmd,
		resp->variable, &count, ccb->sg_count, ST_TO_CMD);
}

static void stex_ys_commands(struct st_hba *hba,
	struct st_ccb *ccb, struct status_msg *resp)
{
	size_t count;

	if (ccb->cmd->cmnd[0] == MGT_CMD &&
		resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
		ccb->cmd->request_bufflen =
			le32_to_cpu(*(__le32 *)&resp->variable[0]);
		return;
	}

	if (resp->srb_status != 0)
		return;

	/* determine inquiry command status by DeviceTypeQualifier */
	if (ccb->cmd->cmnd[0] == INQUIRY &&
		resp->scsi_status == SAM_STAT_GOOD) {
		ST_INQ *inq_data;

		count = STEX_EXTRA_SIZE;
		stex_internal_copy(ccb->cmd, hba->copy_buffer,
			&count, ccb->sg_count, ST_FROM_CMD);
		inq_data = (ST_INQ *)hba->copy_buffer;
		if (inq_data->DeviceTypeQualifier != 0)
			ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
		else
			ccb->srb_status = SRB_STATUS_SUCCESS;
	} else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
		u8 *report_lun_data = (u8 *)hba->copy_buffer;

		count = STEX_EXTRA_SIZE;
		stex_internal_copy(ccb->cmd, report_lun_data,
			&count, ccb->sg_count, ST_FROM_CMD);
		if (report_lun_data[2] || report_lun_data[3]) {
			report_lun_data[2] = 0x00;
			report_lun_data[3] = 0x08;
			stex_internal_copy(ccb->cmd, report_lun_data,
				&count, ccb->sg_count, ST_TO_CMD);
		}
	}
}
}


static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
@@ -701,8 +795,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
		return;
		return;
	}
	}


	if (unlikely(hba->mu_status != MU_STATE_STARTED ||
	/*
		hba->out_req_cnt <= 0)) {
	 * it's not a valid status payload if:
	 * 1. there are no pending requests(e.g. during init stage)
	 * 2. there are some pending requests, but the controller is in
	 *     reset status, and its type is not st_yosemite
	 * firmware of st_yosemite in reset status will return pending requests
	 * to driver, so we allow it to pass
	 */
	if (unlikely(hba->out_req_cnt <= 0 ||
			(hba->mu_status == MU_STATE_RESETTING &&
			 hba->cardtype != st_yosemite))) {
		hba->status_tail = hba->status_head;
		hba->status_tail = hba->status_head;
		goto update_status;
		goto update_status;
	}
	}
@@ -722,6 +825,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
		if (unlikely(ccb->req == NULL)) {
		if (unlikely(ccb->req == NULL)) {
			printk(KERN_WARNING DRV_NAME
			printk(KERN_WARNING DRV_NAME
				"(%s): lagging req\n", pci_name(hba->pdev));
				"(%s): lagging req\n", pci_name(hba->pdev));
			hba->out_req_cnt--;
			continue;
			continue;
		}
		}


@@ -740,9 +844,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
		ccb->scsi_status = resp->scsi_status;
		ccb->scsi_status = resp->scsi_status;


		if (likely(ccb->cmd != NULL)) {
		if (likely(ccb->cmd != NULL)) {
			if (hba->cardtype == st_yosemite)
				stex_ys_commands(hba, ccb, resp);

			if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
			if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
				ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
				ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
				stex_controller_info(hba, ccb);
				stex_controller_info(hba, ccb);

			stex_unmap_sg(hba, ccb->cmd);
			stex_unmap_sg(hba, ccb->cmd);
			stex_scsi_done(ccb);
			stex_scsi_done(ccb);
			hba->out_req_cnt--;
			hba->out_req_cnt--;
@@ -947,6 +1055,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
{
{
	struct st_hba *hba;
	struct st_hba *hba;
	unsigned long flags;
	unsigned long flags;
	unsigned long before;
	hba = (struct st_hba *) &cmd->device->host->hostdata[0];
	hba = (struct st_hba *) &cmd->device->host->hostdata[0];


	hba->mu_status = MU_STATE_RESETTING;
	hba->mu_status = MU_STATE_RESETTING;
@@ -954,6 +1063,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
	if (hba->cardtype == st_shasta)
	if (hba->cardtype == st_shasta)
		stex_hard_reset(hba);
		stex_hard_reset(hba);


	if (hba->cardtype != st_yosemite) {
		if (stex_handshake(hba)) {
		if (stex_handshake(hba)) {
			printk(KERN_WARNING DRV_NAME
			printk(KERN_WARNING DRV_NAME
				"(%s): resetting: handshake failed\n",
				"(%s): resetting: handshake failed\n",
@@ -967,7 +1077,23 @@ static int stex_reset(struct scsi_cmnd *cmd)
		hba->status_tail = 0;
		hba->status_tail = 0;
		hba->out_req_cnt = 0;
		hba->out_req_cnt = 0;
		spin_unlock_irqrestore(hba->host->host_lock, flags);
		spin_unlock_irqrestore(hba->host->host_lock, flags);
		return SUCCESS;
	}

	/* st_yosemite */
	writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
	readl(hba->mmio_base + IDBL); /* flush */
	before = jiffies;
	while (hba->out_req_cnt > 0) {
		if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
			printk(KERN_WARNING DRV_NAME
				"(%s): reset timeout\n", pci_name(hba->pdev));
			return FAILED;
		}
		msleep(1);
	}


	hba->mu_status = MU_STATE_STARTED;
	return SUCCESS;
	return SUCCESS;
}
}


@@ -1155,9 +1281,16 @@ static void stex_hba_stop(struct st_hba *hba)
	req = stex_alloc_req(hba);
	req = stex_alloc_req(hba);
	memset(req->cdb, 0, STEX_CDB_LENGTH);
	memset(req->cdb, 0, STEX_CDB_LENGTH);


	if (hba->cardtype == st_yosemite) {
		req->cdb[0] = MGT_CMD;
		req->cdb[1] = MGT_CMD_SIGNATURE;
		req->cdb[2] = CTLR_CONFIG_CMD;
		req->cdb[3] = CTLR_SHUTDOWN;
	} else {
		req->cdb[0] = CONTROLLER_CMD;
		req->cdb[0] = CONTROLLER_CMD;
		req->cdb[1] = CTLR_POWER_STATE_CHANGE;
		req->cdb[1] = CTLR_POWER_STATE_CHANGE;
		req->cdb[2] = CTLR_POWER_SAVING;
		req->cdb[2] = CTLR_POWER_SAVING;
	}


	hba->ccb[tag].cmd = NULL;
	hba->ccb[tag].cmd = NULL;
	hba->ccb[tag].sg_count = 0;
	hba->ccb[tag].sg_count = 0;
@@ -1221,6 +1354,7 @@ static struct pci_device_id stex_pci_tbl[] = {
	{ 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
	{ 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
	{ 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
	{ 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
	{ 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
	{ 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
	{ 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
	{ }	/* terminate list */
	{ }	/* terminate list */
};
};
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);