aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarish Zunjarrao <harish.zunjarrao@qlogic.com>2010-10-15 14:27:43 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-10-25 17:00:40 -0400
commitf19af1636bda8454401fa76ce4ad027412d5d07a (patch)
tree4f108bd888ce8743584db22206a4dd1a4145fb36
parentff454b01b4ebe60b14092943978000928bf8c551 (diff)
[SCSI] qla2xxx: Add flash read/update support using BSG interface
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>
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c125
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h2
2 files changed, 127 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index fdfbf83a6330..31a4121a2be1 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -1307,6 +1307,125 @@ qla24xx_iidma(struct fc_bsg_job *bsg_job)
1307} 1307}
1308 1308
1309static int 1309static int
1310qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, struct qla_hw_data *ha,
1311 uint8_t is_update)
1312{
1313 uint32_t start = 0;
1314 int valid = 0;
1315
1316 bsg_job->reply->reply_payload_rcv_len = 0;
1317
1318 if (unlikely(pci_channel_offline(ha->pdev)))
1319 return -EINVAL;
1320
1321 start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
1322 if (start > ha->optrom_size)
1323 return -EINVAL;
1324
1325 if (ha->optrom_state != QLA_SWAITING)
1326 return -EBUSY;
1327
1328 ha->optrom_region_start = start;
1329
1330 if (is_update) {
1331 if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
1332 valid = 1;
1333 else if (start == (ha->flt_region_boot * 4) ||
1334 start == (ha->flt_region_fw * 4))
1335 valid = 1;
1336 else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
1337 IS_QLA8XXX_TYPE(ha))
1338 valid = 1;
1339 if (!valid) {
1340 qla_printk(KERN_WARNING, ha,
1341 "Invalid start region 0x%x/0x%x.\n",
1342 start, bsg_job->request_payload.payload_len);
1343 return -EINVAL;
1344 }
1345
1346 ha->optrom_region_size = start +
1347 bsg_job->request_payload.payload_len > ha->optrom_size ?
1348 ha->optrom_size - start :
1349 bsg_job->request_payload.payload_len;
1350 ha->optrom_state = QLA_SWRITING;
1351 } else {
1352 ha->optrom_region_size = start +
1353 bsg_job->reply_payload.payload_len > ha->optrom_size ?
1354 ha->optrom_size - start :
1355 bsg_job->reply_payload.payload_len;
1356 ha->optrom_state = QLA_SREADING;
1357 }
1358
1359 ha->optrom_buffer = vmalloc(ha->optrom_region_size);
1360 if (!ha->optrom_buffer) {
1361 qla_printk(KERN_WARNING, ha,
1362 "Read: Unable to allocate memory for optrom retrieval "
1363 "(%x).\n", ha->optrom_region_size);
1364
1365 ha->optrom_state = QLA_SWAITING;
1366 return -ENOMEM;
1367 }
1368
1369 memset(ha->optrom_buffer, 0, ha->optrom_region_size);
1370 return 0;
1371}
1372
1373static int
1374qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
1375{
1376 struct Scsi_Host *host = bsg_job->shost;
1377 scsi_qla_host_t *vha = shost_priv(host);
1378 struct qla_hw_data *ha = vha->hw;
1379 int rval = 0;
1380
1381 rval = qla2x00_optrom_setup(bsg_job, ha, 0);
1382 if (rval)
1383 return rval;
1384
1385 ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
1386 ha->optrom_region_start, ha->optrom_region_size);
1387
1388 sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
1389 bsg_job->reply_payload.sg_cnt, ha->optrom_buffer,
1390 ha->optrom_region_size);
1391
1392 bsg_job->reply->reply_payload_rcv_len = ha->optrom_region_size;
1393 bsg_job->reply->result = DID_OK;
1394 vfree(ha->optrom_buffer);
1395 ha->optrom_buffer = NULL;
1396 ha->optrom_state = QLA_SWAITING;
1397 bsg_job->job_done(bsg_job);
1398 return rval;
1399}
1400
1401static int
1402qla2x00_update_optrom(struct fc_bsg_job *bsg_job)
1403{
1404 struct Scsi_Host *host = bsg_job->shost;
1405 scsi_qla_host_t *vha = shost_priv(host);
1406 struct qla_hw_data *ha = vha->hw;
1407 int rval = 0;
1408
1409 rval = qla2x00_optrom_setup(bsg_job, ha, 1);
1410 if (rval)
1411 return rval;
1412
1413 sg_copy_to_buffer(bsg_job->request_payload.sg_list,
1414 bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
1415 ha->optrom_region_size);
1416
1417 ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
1418 ha->optrom_region_start, ha->optrom_region_size);
1419
1420 bsg_job->reply->result = DID_OK;
1421 vfree(ha->optrom_buffer);
1422 ha->optrom_buffer = NULL;
1423 ha->optrom_state = QLA_SWAITING;
1424 bsg_job->job_done(bsg_job);
1425 return rval;
1426}
1427
1428static int
1310qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) 1429qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
1311{ 1430{
1312 switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { 1431 switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) {
@@ -1328,6 +1447,12 @@ qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job)
1328 case QL_VND_FCP_PRIO_CFG_CMD: 1447 case QL_VND_FCP_PRIO_CFG_CMD:
1329 return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job); 1448 return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job);
1330 1449
1450 case QL_VND_READ_FLASH:
1451 return qla2x00_read_optrom(bsg_job);
1452
1453 case QL_VND_UPDATE_FLASH:
1454 return qla2x00_update_optrom(bsg_job);
1455
1331 default: 1456 default:
1332 bsg_job->reply->result = (DID_ERROR << 16); 1457 bsg_job->reply->result = (DID_ERROR << 16);
1333 bsg_job->job_done(bsg_job); 1458 bsg_job->job_done(bsg_job);
diff --git a/drivers/scsi/qla2xxx/qla_bsg.h b/drivers/scsi/qla2xxx/qla_bsg.h
index cc7c52f87a11..074a999c7017 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.h
+++ b/drivers/scsi/qla2xxx/qla_bsg.h
@@ -14,6 +14,8 @@
14#define QL_VND_A84_MGMT_CMD 0x04 14#define QL_VND_A84_MGMT_CMD 0x04
15#define QL_VND_IIDMA 0x05 15#define QL_VND_IIDMA 0x05
16#define QL_VND_FCP_PRIO_CFG_CMD 0x06 16#define QL_VND_FCP_PRIO_CFG_CMD 0x06
17#define QL_VND_READ_FLASH 0x07
18#define QL_VND_UPDATE_FLASH 0x08
17 19
18/* BSG definations for interpreting CommandSent field */ 20/* BSG definations for interpreting CommandSent field */
19#define INT_DEF_LB_LOOPBACK_CMD 0 21#define INT_DEF_LB_LOOPBACK_CMD 0