diff options
author | Harish Zunjarrao <harish.zunjarrao@qlogic.com> | 2010-10-15 14:27:43 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-10-25 17:00:40 -0400 |
commit | f19af1636bda8454401fa76ce4ad027412d5d07a (patch) | |
tree | 4f108bd888ce8743584db22206a4dd1a4145fb36 | |
parent | ff454b01b4ebe60b14092943978000928bf8c551 (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.c | 125 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.h | 2 |
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 | ||
1309 | static int | 1309 | static int |
1310 | qla2x00_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 | |||
1373 | static int | ||
1374 | qla2x00_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 | |||
1401 | static int | ||
1402 | qla2x00_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 | |||
1428 | static int | ||
1310 | qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) | 1429 | qla2x00_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 |