]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
[SCSI] qla2xxx: Add EDC-update support.
authorJoe Carnuccio <joe.carnuccio@qlogic.com>
Tue, 24 Mar 2009 16:08:12 +0000 (09:08 -0700)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Fri, 3 Apr 2009 14:22:51 +0000 (09:22 -0500)
Interface allows for the update of onboard EDC firmware
present on mezzanine ISP25xx type cards.

Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c

index c017dba900393f67f3e6bdc984b2724c0962d3f5..877990115f5343d1208628a1853dbf28277b7080 100644 (file)
@@ -548,6 +548,144 @@ static struct bin_attribute sysfs_reset_attr = {
        .write = qla2x00_sysfs_write_reset,
 };
 
+static ssize_t
+qla2x00_sysfs_write_edc(struct kobject *kobj,
+                       struct bin_attribute *bin_attr,
+                       char *buf, loff_t off, size_t count)
+{
+       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+           struct device, kobj)));
+       struct qla_hw_data *ha = vha->hw;
+       uint16_t dev, adr, opt, len;
+       int rval;
+
+       ha->edc_data_len = 0;
+
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
+               return 0;
+
+       if (!ha->edc_data) {
+               ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+                   &ha->edc_data_dma);
+               if (!ha->edc_data) {
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                           "Unable to allocate memory for EDC write.\n"));
+                       return 0;
+               }
+       }
+
+       dev = le16_to_cpup((void *)&buf[0]);
+       adr = le16_to_cpup((void *)&buf[2]);
+       opt = le16_to_cpup((void *)&buf[4]);
+       len = le16_to_cpup((void *)&buf[6]);
+
+       if (!(opt & BIT_0))
+               if (len == 0 || len > DMA_POOL_SIZE || len > count - 8)
+                       return -EINVAL;
+
+       memcpy(ha->edc_data, &buf[8], len);
+
+       rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma,
+           ha->edc_data, len, opt);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n",
+                   rval, dev, adr, opt, len, *buf));
+               return 0;
+       }
+
+       return count;
+}
+
+static struct bin_attribute sysfs_edc_attr = {
+       .attr = {
+               .name = "edc",
+               .mode = S_IWUSR,
+       },
+       .size = 0,
+       .write = qla2x00_sysfs_write_edc,
+};
+
+static ssize_t
+qla2x00_sysfs_write_edc_status(struct kobject *kobj,
+                       struct bin_attribute *bin_attr,
+                       char *buf, loff_t off, size_t count)
+{
+       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+           struct device, kobj)));
+       struct qla_hw_data *ha = vha->hw;
+       uint16_t dev, adr, opt, len;
+       int rval;
+
+       ha->edc_data_len = 0;
+
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8)
+               return 0;
+
+       if (!ha->edc_data) {
+               ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+                   &ha->edc_data_dma);
+               if (!ha->edc_data) {
+                       DEBUG2(qla_printk(KERN_INFO, ha,
+                           "Unable to allocate memory for EDC status.\n"));
+                       return 0;
+               }
+       }
+
+       dev = le16_to_cpup((void *)&buf[0]);
+       adr = le16_to_cpup((void *)&buf[2]);
+       opt = le16_to_cpup((void *)&buf[4]);
+       len = le16_to_cpup((void *)&buf[6]);
+
+       if (!(opt & BIT_0))
+               if (len == 0 || len > DMA_POOL_SIZE)
+                       return -EINVAL;
+
+       memset(ha->edc_data, 0, len);
+       rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma,
+           ha->edc_data, len, opt);
+       if (rval != QLA_SUCCESS) {
+               DEBUG2(qla_printk(KERN_INFO, ha,
+                   "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n",
+                   rval, dev, adr, opt, len));
+               return 0;
+       }
+
+       ha->edc_data_len = len;
+
+       return count;
+}
+
+static ssize_t
+qla2x00_sysfs_read_edc_status(struct kobject *kobj,
+                          struct bin_attribute *bin_attr,
+                          char *buf, loff_t off, size_t count)
+{
+       struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
+           struct device, kobj)));
+       struct qla_hw_data *ha = vha->hw;
+
+       if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0)
+               return 0;
+
+       if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count)
+               return -EINVAL;
+
+       memcpy(buf, ha->edc_data, ha->edc_data_len);
+
+       return ha->edc_data_len;
+}
+
+static struct bin_attribute sysfs_edc_status_attr = {
+       .attr = {
+               .name = "edc_status",
+               .mode = S_IRUSR | S_IWUSR,
+       },
+       .size = 0,
+       .write = qla2x00_sysfs_write_edc_status,
+       .read = qla2x00_sysfs_read_edc_status,
+};
+
 static struct sysfs_entry {
        char *name;
        struct bin_attribute *attr;
@@ -560,6 +698,8 @@ static struct sysfs_entry {
        { "vpd", &sysfs_vpd_attr, 1 },
        { "sfp", &sysfs_sfp_attr, 1 },
        { "reset", &sysfs_reset_attr, },
+       { "edc", &sysfs_edc_attr, 2 },
+       { "edc_status", &sysfs_edc_status_attr, 2 },
        { NULL },
 };
 
@@ -573,6 +713,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
        for (iter = bin_file_entries; iter->name; iter++) {
                if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw))
                        continue;
+               if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw))
+                       continue;
 
                ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
@@ -593,6 +735,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha)
        for (iter = bin_file_entries; iter->name; iter++) {
                if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
                        continue;
+               if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha))
+                       continue;
 
                sysfs_remove_bin_file(&host->shost_gendev.kobj,
                    iter->attr);
index 757e31d62146d0c53f345a78263b098e097f046e..5a55a20207ecf1b5ba3f0169e79a30e067cb151a 100644 (file)
@@ -607,6 +607,7 @@ typedef struct {
 #define MBC_GET_TIMEOUT_PARAMS         0x22    /* Get FW timeouts. */
 #define MBC_TRACE_CONTROL              0x27    /* Trace control command. */
 #define MBC_GEN_SYSTEM_ERROR           0x2a    /* Generate System Error. */
+#define MBC_WRITE_SFP                  0x30    /* Write SFP Data. */
 #define MBC_READ_SFP                   0x31    /* Read SFP Data. */
 #define MBC_SET_TIMEOUT_PARAMS         0x32    /* Set FW timeouts. */
 #define MBC_MID_INITIALIZE_FIRMWARE    0x48    /* MID Initialize firmware. */
@@ -2387,6 +2388,10 @@ struct qla_hw_data {
        void            *sfp_data;
        dma_addr_t      sfp_data_dma;
 
+       uint8_t         *edc_data;
+       dma_addr_t      edc_data_dma;
+       uint16_t        edc_data_len;
+
        struct task_struct      *dpc_thread;
        uint8_t dpc_active;                  /* DPC routine is active */
 
index 41c3f41e68691dc37ad0500f121a0c938ab10381..528913f6bed99ffc010eb3ec6d680660403683c7 100644 (file)
@@ -264,6 +264,14 @@ qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *);
 extern int
 qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
 
+extern int
+qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
+    uint8_t *, uint16_t, uint16_t);
+
+extern int
+qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
+    uint8_t *, uint16_t, uint16_t);
+
 extern int
 qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
 
index 7af9bd73a10dcf8a442fa0aa93fef774dacb1c40..951537e3029406eeabcb669d7ee4b75da7299ee9 100644 (file)
@@ -3347,3 +3347,81 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha)
 
        return rval;
 }
+
+int
+qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr,
+    dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_READ_SFP;
+       mcp->mb[1] = dev;
+       mcp->mb[2] = MSW(sfp_dma);
+       mcp->mb[3] = LSW(sfp_dma);
+       mcp->mb[6] = MSW(MSD(sfp_dma));
+       mcp->mb[7] = LSW(MSD(sfp_dma));
+       mcp->mb[8] = len;
+       mcp->mb[9] = adr;
+       mcp->mb[10] = opt;
+       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (opt & BIT_0)
+               if (sfp)
+                       *sfp = mcp->mb[8];
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+                   vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+       }
+
+       return rval;
+}
+
+int
+qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr,
+    dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       if (opt & BIT_0)
+               if (sfp)
+                       len = *sfp;
+
+       mcp->mb[0] = MBC_WRITE_SFP;
+       mcp->mb[1] = dev;
+       mcp->mb[2] = MSW(sfp_dma);
+       mcp->mb[3] = LSW(sfp_dma);
+       mcp->mb[6] = MSW(MSD(sfp_dma));
+       mcp->mb[7] = LSW(MSD(sfp_dma));
+       mcp->mb[8] = len;
+       mcp->mb[9] = adr;
+       mcp->mb[10] = opt;
+       mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+                   vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
index ba3309f85560609d2474d9257a01b1e034f5e255..9bb4b2ed6608c7972740738743166d9ee646313c 100644 (file)
@@ -2337,6 +2337,9 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        if (ha->sfp_data)
                dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
 
+       if (ha->edc_data)
+               dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma);
+
        if (ha->ms_iocb)
                dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);