[SCSI] qla2xxx: Add EDC-update support.
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>
This commit is contained in:
parent
fbcbb5d0cf
commit
ad0ecd61f4
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 *);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user