[SCSI] be2iscsi: Adding bsg interface for be2iscsi
authorJayamohan Kallickal <jayamohan.kallickal@emulex.com>
Wed, 4 Apr 2012 04:41:50 +0000 (23:41 -0500)
committerJames Bottomley <JBottomley@Parallels.com>
Wed, 25 Apr 2012 08:33:15 +0000 (09:33 +0100)
Signed-off-by: Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
drivers/scsi/be2iscsi/be_cmds.h
drivers/scsi/be2iscsi/be_main.c
drivers/scsi/be2iscsi/be_mgmt.c
drivers/scsi/be2iscsi/be_mgmt.h

index f343ed6..b15de3e 100644 (file)
@@ -822,6 +822,8 @@ struct be_all_if_id {
 #define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41
 #define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
 #define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET  52
+#define OPCODE_COMMON_WRITE_FLASH              96
+#define OPCODE_COMMON_READ_FLASH               97
 
 /* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
 #define CMD_ISCSI_COMMAND_INVALIDATE           1
index d0c7d97..ff6f851 100644 (file)
 #include <linux/semaphore.h>
 #include <linux/iscsi_boot_sysfs.h>
 #include <linux/module.h>
+#include <linux/bsg-lib.h>
 
 #include <scsi/libiscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
+#include <scsi/scsi_netlink.h>
 #include <scsi/scsi_transport_iscsi.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_cmnd.h>
@@ -407,6 +410,8 @@ static struct scsi_host_template beiscsi_sht = {
        .max_sectors = BEISCSI_MAX_SECTORS,
        .cmd_per_lun = BEISCSI_CMD_PER_LUN,
        .use_clustering = ENABLE_CLUSTERING,
+       .vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
+
 };
 
 static struct scsi_transport_template *beiscsi_scsi_transport;
@@ -4135,6 +4140,76 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
        return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
 }
 
+/**
+ * beiscsi_bsg_request - handle bsg request from ISCSI transport
+ * @job: job to handle
+ */
+static int beiscsi_bsg_request(struct bsg_job *job)
+{
+       struct Scsi_Host *shost;
+       struct beiscsi_hba *phba;
+       struct iscsi_bsg_request *bsg_req = job->request;
+       int rc = -EINVAL;
+       unsigned int tag;
+       struct be_dma_mem nonemb_cmd;
+       struct be_cmd_resp_hdr *resp;
+       struct iscsi_bsg_reply *bsg_reply = job->reply;
+       unsigned short status, extd_status;
+
+       shost = iscsi_job_to_shost(job);
+       phba = iscsi_host_priv(shost);
+
+       switch (bsg_req->msgcode) {
+       case ISCSI_BSG_HST_VENDOR:
+               nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
+                                       job->request_payload.payload_len,
+                                       &nonemb_cmd.dma);
+               if (nonemb_cmd.va == NULL) {
+                       SE_DEBUG(DBG_LVL_1, "Failed to allocate memory for "
+                                "beiscsi_bsg_request\n");
+                       return -EIO;
+               }
+               tag = mgmt_vendor_specific_fw_cmd(&phba->ctrl, phba, job,
+                                                 &nonemb_cmd);
+               if (!tag) {
+                       SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n");
+                       pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                           nonemb_cmd.va, nonemb_cmd.dma);
+                       return -EAGAIN;
+               } else
+                       wait_event_interruptible(phba->ctrl.mcc_wait[tag],
+                                                phba->ctrl.mcc_numtag[tag]);
+               extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8;
+               status = phba->ctrl.mcc_numtag[tag] & 0x000000FF;
+               free_mcc_tag(&phba->ctrl, tag);
+               resp = (struct be_cmd_resp_hdr *)nonemb_cmd.va;
+               sg_copy_from_buffer(job->reply_payload.sg_list,
+                                   job->reply_payload.sg_cnt,
+                                   nonemb_cmd.va, (resp->response_length
+                                   + sizeof(*resp)));
+               bsg_reply->reply_payload_rcv_len = resp->response_length;
+               bsg_reply->result = status;
+               bsg_job_done(job, bsg_reply->result,
+                            bsg_reply->reply_payload_rcv_len);
+               pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size,
+                                   nonemb_cmd.va, nonemb_cmd.dma);
+               if (status || extd_status) {
+                       SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed"
+                                " status = %d extd_status = %d\n",
+                                status, extd_status);
+                       return -EIO;
+               }
+               break;
+
+       default:
+               SE_DEBUG(DBG_LVL_1, "Unsupported bsg command: 0x%x\n",
+                        bsg_req->msgcode);
+               break;
+       }
+
+       return rc;
+}
+
 static void beiscsi_quiesce(struct beiscsi_hba *phba)
 {
        struct hwi_controller *phwi_ctrlr;
@@ -4447,6 +4522,7 @@ struct iscsi_transport beiscsi_iscsi_transport = {
        .ep_poll = beiscsi_ep_poll,
        .ep_disconnect = beiscsi_ep_disconnect,
        .session_recovery_timedout = iscsi_session_recovery_timedout,
+       .bsg_request = beiscsi_bsg_request,
 };
 
 static struct pci_driver beiscsi_pci_driver = {
index f7d27e9..ccc3852 100644 (file)
  * Costa Mesa, CA 92626
  */
 
+#include <linux/bsg-lib.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_bsg_iscsi.h>
 #include "be_mgmt.h"
 #include "be_iscsi.h"
-#include <scsi/scsi_transport_iscsi.h>
 
 unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba)
 {
@@ -187,6 +189,72 @@ int mgmt_check_supported_fw(struct be_ctrl_info *ctrl,
        return status;
 }
 
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+                                        struct beiscsi_hba *phba,
+                                        struct bsg_job *job,
+                                        struct be_dma_mem *nonemb_cmd)
+{
+       struct be_cmd_resp_hdr *resp;
+       struct be_mcc_wrb *wrb = wrb_from_mccq(phba);
+       struct be_sge *mcc_sge = nonembedded_sgl(wrb);
+       unsigned int tag = 0;
+       struct iscsi_bsg_request *bsg_req = job->request;
+       struct be_bsg_vendor_cmd *req = nonemb_cmd->va;
+       unsigned short region, sector_size, sector, offset;
+
+       nonemb_cmd->size = job->request_payload.payload_len;
+       memset(nonemb_cmd->va, 0, nonemb_cmd->size);
+       resp = nonemb_cmd->va;
+       region =  bsg_req->rqst_data.h_vendor.vendor_cmd[1];
+       sector_size =  bsg_req->rqst_data.h_vendor.vendor_cmd[2];
+       sector =  bsg_req->rqst_data.h_vendor.vendor_cmd[3];
+       offset =  bsg_req->rqst_data.h_vendor.vendor_cmd[4];
+       req->region = region;
+       req->sector = sector;
+       req->offset = offset;
+       spin_lock(&ctrl->mbox_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) {
+       case BEISCSI_WRITE_FLASH:
+               offset = sector * sector_size + offset;
+               be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+                                  OPCODE_COMMON_WRITE_FLASH, sizeof(*req));
+               sg_copy_to_buffer(job->request_payload.sg_list,
+                                 job->request_payload.sg_cnt,
+                                 nonemb_cmd->va + offset, job->request_len);
+               break;
+       case BEISCSI_READ_FLASH:
+               be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+                          OPCODE_COMMON_READ_FLASH, sizeof(*req));
+               break;
+       default:
+               shost_printk(KERN_WARNING, phba->shost,
+                            "Unsupported cmd = 0x%x\n\n", bsg_req->rqst_data.
+                            h_vendor.vendor_cmd[0]);
+               spin_unlock(&ctrl->mbox_lock);
+               return -ENOSYS;
+       }
+
+       tag = alloc_mcc_tag(phba);
+       if (!tag) {
+               spin_unlock(&ctrl->mbox_lock);
+               return tag;
+       }
+
+       be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false,
+                          job->request_payload.sg_cnt);
+       mcc_sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+       mcc_sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+       mcc_sge->len = cpu_to_le32(nonemb_cmd->size);
+       wrb->tag0 |= tag;
+
+       be_mcc_notify(phba);
+
+       spin_unlock(&ctrl->mbox_lock);
+       return tag;
+}
+
 int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
 {
        struct be_ctrl_info *ctrl = &phba->ctrl;
index d7fdfce..03400f3 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
+#include <scsi/scsi_bsg_iscsi.h>
 #include "be_iscsi.h"
 #include "be_main.h"
 
@@ -98,6 +99,10 @@ unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba,
                                struct invalidate_command_table *inv_tbl,
                                unsigned int num_invalidate, unsigned int cid,
                                struct be_dma_mem *nonemb_cmd);
+unsigned int mgmt_vendor_specific_fw_cmd(struct be_ctrl_info *ctrl,
+                                        struct beiscsi_hba *phba,
+                                        struct bsg_job *job,
+                                        struct be_dma_mem *nonemb_cmd);
 
 struct iscsi_invalidate_connection_params_in {
        struct be_cmd_req_hdr hdr;
@@ -204,6 +209,13 @@ struct be_mgmt_controller_attributes_resp {
        struct mgmt_controller_attributes params;
 } __packed;
 
+struct be_bsg_vendor_cmd {
+       struct be_cmd_req_hdr hdr;
+       unsigned short region;
+       unsigned short offset;
+       unsigned short sector;
+} __packed;
+
 /* configuration management */
 
 #define GET_MGMT_CONTROLLER_WS(phba)    (phba->pmgmt_ws)
@@ -225,6 +237,9 @@ struct be_mgmt_controller_attributes_resp {
                                        bus_address.u.a32.address_hi;  \
 }
 
+#define BEISCSI_WRITE_FLASH 0
+#define BEISCSI_READ_FLASH 1
+
 struct beiscsi_endpoint {
        struct beiscsi_hba *phba;
        struct beiscsi_sess *sess;