Skip to content

Commit

Permalink
[SCSI] qla2xxx: Add flash read/update support using BSG interface
Browse files Browse the repository at this point in the history
Signed-off-by: Harish Zunjarrao <harish.zunjarrao@qlogic.com>
Signed-off-by: Madhuranath Iyengar <Madhu.Iyengar@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Harish Zunjarrao authored and James Bottomley committed Oct 25, 2010
1 parent ff454b0 commit f19af16
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
125 changes: 125 additions & 0 deletions drivers/scsi/qla2xxx/qla_bsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,125 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
return rval;
}

static int
qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
uint8_t is_update)
{
uint32_t start = 0;
int valid = 0;

bsg_job->reply->reply_payload_rcv_len = 0;

if (unlikely(pci_channel_offline(ha->pdev)))
return -EINVAL;

start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
if (start > ha->optrom_size)
return -EINVAL;

if (ha->optrom_state != QLA_SWAITING)
return -EBUSY;

ha->optrom_region_start = start;

if (is_update) {
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
valid = 1;
else if (start == (ha->flt_region_boot * 4) ||
start == (ha->flt_region_fw * 4))
valid = 1;
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
IS_QLA8XXX_TYPE(ha))
valid = 1;
if (!valid) {
qla_printk(KERN_WARNING, ha,
"Invalid start region 0x%x/0x%x.\n",
start, bsg_job->request_payload.payload_len);
return -EINVAL;
}

ha->optrom_region_size = start +
bsg_job->request_payload.payload_len > ha->optrom_size ?
ha->optrom_size - start :
bsg_job->request_payload.payload_len;
ha->optrom_state = QLA_SWRITING;
} else {
ha->optrom_region_size = start +
bsg_job->reply_payload.payload_len > ha->optrom_size ?
ha->optrom_size - start :
bsg_job->reply_payload.payload_len;
ha->optrom_state = QLA_SREADING;
}

ha->optrom_buffer = vmalloc(ha->optrom_region_size);
if (!ha->optrom_buffer) {
qla_printk(KERN_WARNING, ha,
"Read: Unable to allocate memory for optrom retrieval "
"(%x).\n", ha->optrom_region_size);

ha->optrom_state = QLA_SWAITING;
return -ENOMEM;
}

memset(ha->optrom_buffer, 0, ha->optrom_region_size);
return 0;
}

static int
qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
{
struct Scsi_Host *host = bsg_job->shost;
scsi_qla_host_t *vha = shost_priv(host);
struct qla_hw_data *ha = vha->hw;
int rval = 0;

rval = qla2x00_optrom_setup(bsg_job, ha, 0);
if (rval)
return rval;

ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size);

sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,
ha->optrom_region_size);

bsg_job->reply->reply_payload_rcv_len = ha->optrom_region_size;
bsg_job->reply->result = DID_OK;
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
bsg_job->job_done(bsg_job);
return rval;
}

static int
qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
{
struct Scsi_Host *host = bsg_job->shost;
scsi_qla_host_t *vha = shost_priv(host);
struct qla_hw_data *ha = vha->hw;
int rval = 0;

rval = qla2x00_optrom_setup(bsg_job, ha, 1);
if (rval)
return rval;

sg_copy_to_buffer(bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
ha->optrom_region_size);

ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
ha->optrom_region_start, ha->optrom_region_size);

bsg_job->reply->result = DID_OK;
vfree(ha->optrom_buffer);
ha->optrom_buffer = NULL;
ha->optrom_state = QLA_SWAITING;
bsg_job->job_done(bsg_job);
return rval;
}

static int
qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
{
Expand All @@ -1328,6 +1447,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
case QL_VND_FCP_PRIO_CFG_CMD:
return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);

case QL_VND_READ_FLASH:
return qla2x00_read_optrom(bsg_job);

case QL_VND_UPDATE_FLASH:
return qla2x00_update_optrom(bsg_job);

default:
bsg_job->reply->result = (DID_ERROR << 16);
bsg_job->job_done(bsg_job);
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/qla2xxx/qla_bsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#define QL_VND_A84_MGMT_CMD 0x04
#define QL_VND_IIDMA 0x05
#define QL_VND_FCP_PRIO_CFG_CMD 0x06
#define QL_VND_READ_FLASH 0x07
#define QL_VND_UPDATE_FLASH 0x08

/* BSG definations for interpreting CommandSent field */
#define INT_DEF_LB_LOOPBACK_CMD 0
Expand Down

0 comments on commit f19af16

Please sign in to comment.