[PATCH 13/15] qla4xxx: Added bsg support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Added BSG support to enable application support to configure
ISP40XX/ISP82XX adapter.

This patch is on top of: http://marc.info/?l=linux-scsi&m=126999297630764&w=2

Signed-off-by: Vikas Chaudhary <vikas.chaudhary@xxxxxxxxxx>
Signed-off-by: Ravi Anand <ravi.anand@xxxxxxxxxx>
---
 drivers/scsi/qla4xxx/ql4_def.h  |   45 +++++++
 drivers/scsi/qla4xxx/ql4_glbl.h |   18 +++
 drivers/scsi/qla4xxx/ql4_mbx.c  |  262 ++++++++++++++++++++++++++++++++++++++-
 drivers/scsi/qla4xxx/ql4_os.c   |  218 ++++++++++++++++++++++++++++++++
 4 files changed, 541 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
index f28e822..b227bbc 100644
--- a/drivers/scsi/qla4xxx/ql4_def.h
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -584,6 +584,51 @@ struct scsi_qla_host {
 	struct completion mbx_intr_comp;
 };
 
+struct qla4xxx_dma_mem {
+	void *va;
+	dma_addr_t dma;
+	uint32_t size;
+	uint32_t req_sg_cnt;
+	uint32_t rsp_sg_cnt;
+};
+
+struct qla4xxx_bsg_cmd {
+	uint32_t opcode;
+	uint32_t subcode;
+	uint32_t instance;
+	uint32_t data_size;
+	uint32_t offset;
+	uint32_t option0;
+	uint32_t option1;
+	uint32_t option2;
+	uint32_t option3;
+};
+
+enum ql4_vendor_priv_cmd {
+	QL4_GET_DATA,
+	QL4_SET_DATA,
+	QL4_RESTORE_FACTORY_DEF,
+	QL4_DISABLE_ACB,
+};
+
+enum ql4_get_data_cmd {
+	QL4_GET_FLASH,
+	QL4_GET_DDB_DEF,
+	QL4_GET_DDB,
+	QL4_GET_IFCB_DEF,
+	QL4_GET_IFCB,
+	QL4_GET_ACB,
+	QL4_GET_ISCSI_STAT,
+};
+
+enum ql4_set_data_cmd {
+	QL4_SET_FLASH,
+	QL4_SET_DDB,
+	QL4_SET_IFCB,
+	QL4_SET_ACB,
+	QL4_RESET_ISCSI_STAT,
+};
+
 static inline int is_ipv4_enabled(struct scsi_qla_host *ha)
 {
 	return ((ha->ipv4_options & IPOPT_IPv4_PROTOCOL_ENABLE) != 0);
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
index 9aecfdf..4140dfd 100644
--- a/drivers/scsi/qla4xxx/ql4_glbl.h
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -38,6 +38,24 @@ int qla4xxx_get_firmware_state(struct scsi_qla_host *ha, uint32_t *status);
 int qla4xxx_initialize_fw_cb(struct scsi_qla_host *ha);
 int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t *mbox_status);
 int qla4xxx_get_ddb_info(struct scsi_qla_host *ha, uint32_t *mbox_status);
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+		dma_addr_t dma_addr);
+int qla4xxx_bsg_get_ifcb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+		uint32_t sub_cmd);
+int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+		uint32_t instance, uint32_t data_len);
+int qla4xxx_get_iscsi_stat(struct scsi_qla_host *ha, uint32_t device_index,
+		dma_addr_t data_dma);
+int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
+		uint32_t offset, uint32_t option, uint32_t data_len);
+int qla4xxx_bsg_set_ifcb(struct scsi_qla_host *ha, dma_addr_t data_dma);
+int qla4xxx_set_acb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+		uint32_t instance, uint32_t acb_len);
+int qla4xxx_reset_iscsi_stat(struct scsi_qla_host *ha, uint32_t device_index);
+int qla4xxx_restore_factory_defaults(struct iscsi_bsg_job *job,
+		struct qla4xxx_bsg_cmd *qla4xxx_cmd);
+int qla4xxx_disable_acb(struct iscsi_bsg_job *bsg_job,
+		struct qla4xxx_bsg_cmd *qla4xxx_cmd);
 
 /* FIXME: Goodness!  this really wants a small struct to hold the
  * parameters. On x86 the args will get passed on the stack! */
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
index 7dd28d5..524d03e 100644
--- a/drivers/scsi/qla4xxx/ql4_mbx.c
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -1040,8 +1040,8 @@ int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
 	return QLA_SUCCESS;
 }
 
-static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
-				   dma_addr_t dma_addr)
+int qla4xxx_get_default_ddb(struct scsi_qla_host *ha,
+		dma_addr_t dma_addr)
 {
 	uint32_t mbox_cmd[MBOX_REG_COUNT];
 	uint32_t mbox_sts[MBOX_REG_COUNT];
@@ -1209,3 +1209,261 @@ exit_ddb_info:
 	memcpy(mbox_status, mbox_sts, sizeof(mbox_sts));
 	return status;
 }
+
+int qla4xxx_bsg_get_ifcb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+    uint32_t sub_cmd)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	switch (sub_cmd) {
+	case QL4_GET_IFCB_DEF:
+		mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS;
+		break;
+	case QL4_GET_IFCB:
+		mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+		break;
+	}
+
+	mbox_cmd[2] = LSDW(data_dma);
+	mbox_cmd[3] = MSDW(data_dma);
+	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		printk("scsi%ld: %s: "
+		    "Failed to get init_fw_ctrl_blk, staus: %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]);
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+    uint32_t instance, uint32_t data_len)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_GET_ACB;
+	mbox_cmd[1] = instance;  /* Primary/Secondary */
+	mbox_cmd[2] = LSDW(data_dma);
+	mbox_cmd[3] = MSDW(data_dma);
+	mbox_cmd[4] = data_len;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		printk("scsi%ld: %s: "
+		    "Failed to get acb, staus: %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]);
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_get_iscsi_stat(struct scsi_qla_host *ha, uint32_t device_index,
+    dma_addr_t data_dma)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_GET_MANAGEMENT_DATA;
+	mbox_cmd[1] = device_index;
+	mbox_cmd[2] = LSDW(data_dma);
+	mbox_cmd[3] = MSDW(data_dma);
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_MANAGEMENT_DATA,"
+		    " failed w/ status %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
+    uint32_t offset, uint32_t option, uint32_t data_len)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_WRITE_FLASH;
+	mbox_cmd[1] = LSDW(dma_addr);
+	mbox_cmd[2] = MSDW(dma_addr);
+	mbox_cmd[3] = offset;
+	mbox_cmd[4] = data_len;
+	mbox_cmd[5] = option;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		printk("scsi%ld: %s: "
+		    "MBOX_CMD_WRITE_FLASH failed w/ status %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]);
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_bsg_set_ifcb(struct scsi_qla_host *ha, dma_addr_t data_dma)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
+	mbox_cmd[1] = 0;
+	mbox_cmd[2] = LSDW(data_dma);
+	mbox_cmd[3] = MSDW(data_dma);
+	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk);
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE,"
+		    " failed w/ status %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_set_acb(struct scsi_qla_host *ha, dma_addr_t data_dma,
+		uint32_t instance, uint32_t acb_len)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_SET_ACB;
+	mbox_cmd[1] = instance;
+	mbox_cmd[2] = LSDW(data_dma);
+	mbox_cmd[3] = MSDW(data_dma);
+	mbox_cmd[4] = acb_len;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_SET_ACB, failed w/ "
+		    "status %04X\n", ha->host_no, __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_reset_iscsi_stat(struct scsi_qla_host *ha, uint32_t device_index)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_GET_MANAGEMENT_DATA;
+	mbox_cmd[1] = device_index;
+	mbox_cmd[2] = 0;
+	mbox_cmd[3] = 0;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_MANAGEMENT_DATA,"
+		    " failed w/ status %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]));
+		    return QLA_ERROR;
+	}
+
+	return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_restore_factory_defaults - restore hba factory defaults
+ * @job: iscsi_bsg_job to handle
+ **/
+int qla4xxx_restore_factory_defaults(struct iscsi_bsg_job *bsg_job,
+    struct qla4xxx_bsg_cmd *qla4xxx_cmd)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+	struct scsi_qla_host *ha = to_qla_host(bsg_job->shost);
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_RESTORE_FACTORY_DEFAULTS;
+	mbox_cmd[3] = qla4xxx_cmd->option0;
+	mbox_cmd[4] = qla4xxx_cmd->option1;
+	mbox_cmd[5] = qla4xxx_cmd->option2;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_RESTORE_FACTORY_DEFAULTS,"
+		    " failed w/ status %04X\n",
+		    ha->host_no, __func__, mbox_sts[0]));
+		return QLA_ERROR;
+	}
+	return QLA_SUCCESS;
+}
+
+int qla4xxx_disable_acb(struct iscsi_bsg_job *bsg_job,
+    struct qla4xxx_bsg_cmd *qla4xxx_cmd)
+{
+	uint32_t mbox_cmd[MBOX_REG_COUNT];
+	uint32_t mbox_sts[MBOX_REG_COUNT];
+	struct scsi_qla_host *ha = to_qla_host(bsg_job->shost);
+	int ret = QLA_SUCCESS;
+
+	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+	memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+	mbox_cmd[0] = MBOX_CMD_DISABLE_ACB;
+	mbox_cmd[1] = qla4xxx_cmd->instance;
+
+	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
+	    &mbox_sts[0]) != QLA_SUCCESS) {
+		if (mbox_sts[0] == MBOX_STS_INTERMEDIATE_COMPLETION) {
+			unsigned long  wait_cnt;
+			wait_cnt = jiffies + (WAIT_CMD_TOV * HZ);
+
+			while (time_before(jiffies, wait_cnt)) {
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(HZ);
+
+				memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+				memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+				mbox_cmd[0] = MBOX_CMD_GET_IP_ADDR_STATE;
+				mbox_cmd[1] = qla4xxx_cmd->instance;
+
+				if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT,
+				    2, &mbox_cmd[0], &mbox_sts[0]) ==
+				    QLA_SUCCESS) {
+					if (!(mbox_sts[1] & 0xF0000000))
+						break;
+				} else {
+					DEBUG2(printk("scsi%ld: %s: Command "
+					    "failed\n", ha->host_no,
+					    __func__));
+					ret = QLA_ERROR;
+					break;
+				}
+			}
+		} else
+			ret = QLA_ERROR;
+	}
+	return ret;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 56d22b8..c59e832 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -9,6 +9,8 @@
 
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsicam.h>
+#include <scsi/scsi_bsg_iscsi.h>
+#include <scsi/scsi_netlink.h>
 
 #include "ql4_def.h"
 #include "ql4_version.h"
@@ -75,6 +77,7 @@ static int qla4xxx_host_get_param(struct Scsi_Host *shost,
 				  enum iscsi_host_param param, char *buf);
 static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
 static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc);
+static int qla4xxx_bsg_request(struct iscsi_bsg_job *job);
 
 /*
  * SCSI host template entry points
@@ -118,6 +121,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
 	.sg_tablesize		= SG_ALL,
 
 	.max_sectors		= 0xFFFF,
+	.vendor_id		= SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
 	.shost_attrs            = qla4xxx_host_attrs,
 };
 
@@ -142,10 +146,224 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
 	.get_session_param	= qla4xxx_sess_get_param,
 	.get_host_param		= qla4xxx_host_get_param,
 	.session_recovery_timedout = qla4xxx_recovery_timedout,
+	.bsg_request		= qla4xxx_bsg_request,
 };
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+/**
+ * qla4xxx_get_data - data from driver to application
+ * @job: iscsi_bsg_job to handle
+ **/
+static int qla4xxx_get_data(struct iscsi_bsg_job *bsg_job,
+    struct qla4xxx_bsg_cmd *qla4xxx_cmd,
+    struct qla4xxx_dma_mem mem)
+{
+	int rval = QLA_SUCCESS;
+	struct scsi_qla_host *ha = to_qla_host(bsg_job->shost);
+
+	switch (qla4xxx_cmd->subcode) {
+	case QL4_GET_FLASH:
+		rval = qla4xxx_get_flash(ha, mem.dma, qla4xxx_cmd->offset,
+		    mem.size);
+		break;
+	case QL4_GET_DDB_DEF:
+		rval = qla4xxx_get_default_ddb(ha, mem.dma);
+		break;
+	case QL4_GET_DDB:
+		rval = qla4xxx_get_fwddb_entry(ha, qla4xxx_cmd->instance,
+		    NULL, mem.dma, NULL, NULL,
+		    NULL, NULL, NULL, NULL);
+		break;
+	case QL4_GET_IFCB_DEF:
+	case QL4_GET_IFCB:
+		rval = qla4xxx_bsg_get_ifcb(ha, mem.dma,
+		    qla4xxx_cmd->subcode);
+		break;
+	case QL4_GET_ACB:
+		rval = qla4xxx_get_acb(ha, mem.dma, qla4xxx_cmd->instance,
+		    mem.size);
+		break;
+	case QL4_GET_ISCSI_STAT:
+		rval = qla4xxx_get_iscsi_stat(ha, qla4xxx_cmd->instance,
+		    mem.dma);
+		break;
+	default:
+		DEBUG2(printk("scsi %ld: %s: invalid sub command code: 0x%x\n",
+		    ha->host_no, __func__, qla4xxx_cmd->opcode));
+		rval = -EINVAL;
+	}
+
+	bsg_job->reply->reply_payload_rcv_len = mem.size;
+	return rval;
+}
+
+/**
+ * qla4xxx_set_data - data from application to driver
+ * @ha: Pointer to host adapter structure.
+ * @job: iscsi_bsg_job to handle
+ * @vendor_cmd: bsg vendor specific command structure
+ * @data: data buffer
+ * @data_dma: DMA address of data buffer
+ **/
+static int qla4xxx_set_data(struct iscsi_bsg_job *bsg_job,
+    struct qla4xxx_bsg_cmd *qla4xxx_cmd,
+    struct qla4xxx_dma_mem mem)
+{
+	int rval = QLA_SUCCESS;
+	struct scsi_qla_host *ha = to_qla_host(bsg_job->shost);
+
+	/* Copy the request buffer in req_data now */
+	sg_copy_to_buffer(bsg_job->request_payload.sg_list,
+	    bsg_job->request_payload.sg_cnt, mem.va,
+	    mem.size);
+
+	switch (qla4xxx_cmd->subcode) {
+	case QL4_SET_FLASH:
+		rval = qla4xxx_set_flash(ha, mem.dma, qla4xxx_cmd->offset,
+		    qla4xxx_cmd->option0, mem.size);
+		break;
+	case QL4_SET_DDB:
+		rval = qla4xxx_set_ddb_entry(ha, qla4xxx_cmd->instance,
+		    mem.dma);
+		break;
+	case QL4_SET_IFCB:
+		rval = qla4xxx_bsg_set_ifcb(ha, mem.dma);
+		break;
+	case QL4_SET_ACB:
+		rval = qla4xxx_set_acb(ha, mem.dma, qla4xxx_cmd->instance,
+		    mem.size);
+		break;
+	case QL4_RESET_ISCSI_STAT:
+		rval = qla4xxx_reset_iscsi_stat(ha, qla4xxx_cmd->instance);
+		break;
+	default:
+		DEBUG2(printk("scsi %ld: %s: invalid sub command code: 0x%x\n",
+		    ha->host_no, __func__, qla4xxx_cmd->opcode));
+		rval = -EINVAL;
+	}
+	bsg_job->reply->reply_payload_rcv_len = 0;
+	return rval;
+}
+
+/**
+ * qla4xxx_process_vendor_specific - handle vendor specific bsg request
+ * @job: iscsi_bsg_job to handle
+ **/
+static int qla4xxx_process_vendor_specific(struct iscsi_bsg_job *bsg_job)
+{
+	struct scsi_qla_host *ha = to_qla_host(bsg_job->shost);
+	struct qla4xxx_bsg_cmd *qla4xxx_cmd;
+	struct qla4xxx_dma_mem mem;
+	int rval = QLA_SUCCESS;
+
+	qla4xxx_cmd = (struct qla4xxx_bsg_cmd *) ((char *)bsg_job->request +
+	    sizeof(struct iscsi_bsg_request));
+
+	mem.req_sg_cnt =
+		dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
+		    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+	if (!mem.req_sg_cnt) {
+		rval = -ENOMEM;
+		goto done;
+	}
+
+	mem.rsp_sg_cnt =
+		dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list,
+		    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+
+	if (!mem.rsp_sg_cnt) {
+		rval = -ENOMEM;
+		goto done;
+	}
+
+	if ((mem.req_sg_cnt != bsg_job->request_payload.sg_cnt) ||
+	    (mem.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) {
+		DEBUG2(printk(KERN_INFO
+		    "dma mapping resulted in different sg counts \
+		    [request_sg_cnt: %x dma_request_sg_cnt: %x\
+		    reply_sg_cnt: %x dma_reply_sg_cnt: %x]\n",
+		    bsg_job->request_payload.sg_cnt, mem.req_sg_cnt,
+		    bsg_job->reply_payload.sg_cnt, mem.rsp_sg_cnt));
+
+		rval = -EAGAIN;
+		goto done_unmap_sg;
+	}
+
+	mem.size = qla4xxx_cmd->data_size;
+	mem.va = dma_alloc_coherent(&ha->pdev->dev, mem.size,
+	    &mem.dma, GFP_KERNEL);
+	if (mem.va == NULL) {
+		DEBUG2(printk("scsi %ld: %s: fail to allocate dma memory "
+		    "for data", ha->host_no, __func__));
+		rval = -EIO;
+		goto done_free_dma;
+	}
+
+	switch (qla4xxx_cmd->opcode) {
+	case QL4_GET_DATA:
+		rval = qla4xxx_get_data(bsg_job, qla4xxx_cmd, mem);
+		break;
+	case QL4_SET_DATA:
+		rval = qla4xxx_set_data(bsg_job, qla4xxx_cmd, mem);
+		break;
+	case QL4_RESTORE_FACTORY_DEF:
+		rval = qla4xxx_restore_factory_defaults(bsg_job, qla4xxx_cmd);
+		break;
+	case QL4_DISABLE_ACB:
+		rval = qla4xxx_disable_acb(bsg_job, qla4xxx_cmd);
+		break;
+	default:
+		DEBUG2(printk("scsi %ld: %s: invalid command code: 0x%x\n",
+		    ha->host_no, __func__, qla4xxx_cmd->opcode));
+		rval = -EINVAL;
+	}
+	bsg_job->reply->result = rval;
+	bsg_job->job_done(bsg_job);
+
+done_free_dma:
+	dma_free_coherent(&ha->pdev->dev, mem.size, mem.va, mem.dma);
+done_unmap_sg:
+	dma_unmap_sg(&ha->pdev->dev,
+	    bsg_job->request_payload.sg_list,
+	    bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
+
+	dma_unmap_sg(&ha->pdev->dev,
+	    bsg_job->reply_payload.sg_list,
+	    bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
+done:
+	return rval;
+}
+
+/**
+ * qla4xxx_bsg_request - handle bsg request from ISCSI transport
+ * @job: iscsi_bsg_job to handle
+ **/
+static int qla4xxx_bsg_request(struct iscsi_bsg_job *job)
+{
+	uint32_t msgcode;
+	int rval = -EINVAL;
+
+	msgcode = job->request->msgcode;
+
+	switch (msgcode) {
+	case ISCSI_BSG_HST_VENDOR:
+		rval = qla4xxx_process_vendor_specific(job);
+		break;
+	case ISCSI_BSG_HST_NET_CONFIG:
+		printk(KERN_ERR "ISCSI_BSG_HST_NET_CONFIG Commands "
+		    "NOT Supported\n");
+		rval = -ENOSYS;
+		break;
+	default:
+		rval = -EINVAL;
+		break;
+	}
+
+	return rval;
+}
+
 static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc)
 {
 	struct iscsi_cls_session *session;
-- 
1.7.0.5

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux