diff options
author | Joe Carnuccio <joe.carnuccio@qlogic.com> | 2009-03-24 12:08:12 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:22:51 -0400 |
commit | ad0ecd61f4ad3260ca8f7216765ddbb1a10677ea (patch) | |
tree | 4a228bd11305a1c07647b948e571542ac9b9389c /drivers | |
parent | fbcbb5d0cf69ba8b59028ec3c5b9f9ff04409b88 (diff) |
[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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 144 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 5 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 8 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_mbx.c | 78 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 3 |
5 files changed, 238 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index c017dba90039..877990115f53 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -548,6 +548,144 @@ static struct bin_attribute sysfs_reset_attr = { | |||
548 | .write = qla2x00_sysfs_write_reset, | 548 | .write = qla2x00_sysfs_write_reset, |
549 | }; | 549 | }; |
550 | 550 | ||
551 | static ssize_t | ||
552 | qla2x00_sysfs_write_edc(struct kobject *kobj, | ||
553 | struct bin_attribute *bin_attr, | ||
554 | char *buf, loff_t off, size_t count) | ||
555 | { | ||
556 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
557 | struct device, kobj))); | ||
558 | struct qla_hw_data *ha = vha->hw; | ||
559 | uint16_t dev, adr, opt, len; | ||
560 | int rval; | ||
561 | |||
562 | ha->edc_data_len = 0; | ||
563 | |||
564 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) | ||
565 | return 0; | ||
566 | |||
567 | if (!ha->edc_data) { | ||
568 | ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, | ||
569 | &ha->edc_data_dma); | ||
570 | if (!ha->edc_data) { | ||
571 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
572 | "Unable to allocate memory for EDC write.\n")); | ||
573 | return 0; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | dev = le16_to_cpup((void *)&buf[0]); | ||
578 | adr = le16_to_cpup((void *)&buf[2]); | ||
579 | opt = le16_to_cpup((void *)&buf[4]); | ||
580 | len = le16_to_cpup((void *)&buf[6]); | ||
581 | |||
582 | if (!(opt & BIT_0)) | ||
583 | if (len == 0 || len > DMA_POOL_SIZE || len > count - 8) | ||
584 | return -EINVAL; | ||
585 | |||
586 | memcpy(ha->edc_data, &buf[8], len); | ||
587 | |||
588 | rval = qla2x00_write_edc(vha, dev, adr, ha->edc_data_dma, | ||
589 | ha->edc_data, len, opt); | ||
590 | if (rval != QLA_SUCCESS) { | ||
591 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
592 | "Unable to write EDC (%x) %02x:%02x:%04x:%02x:%02x.\n", | ||
593 | rval, dev, adr, opt, len, *buf)); | ||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | return count; | ||
598 | } | ||
599 | |||
600 | static struct bin_attribute sysfs_edc_attr = { | ||
601 | .attr = { | ||
602 | .name = "edc", | ||
603 | .mode = S_IWUSR, | ||
604 | }, | ||
605 | .size = 0, | ||
606 | .write = qla2x00_sysfs_write_edc, | ||
607 | }; | ||
608 | |||
609 | static ssize_t | ||
610 | qla2x00_sysfs_write_edc_status(struct kobject *kobj, | ||
611 | struct bin_attribute *bin_attr, | ||
612 | char *buf, loff_t off, size_t count) | ||
613 | { | ||
614 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
615 | struct device, kobj))); | ||
616 | struct qla_hw_data *ha = vha->hw; | ||
617 | uint16_t dev, adr, opt, len; | ||
618 | int rval; | ||
619 | |||
620 | ha->edc_data_len = 0; | ||
621 | |||
622 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count < 8) | ||
623 | return 0; | ||
624 | |||
625 | if (!ha->edc_data) { | ||
626 | ha->edc_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, | ||
627 | &ha->edc_data_dma); | ||
628 | if (!ha->edc_data) { | ||
629 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
630 | "Unable to allocate memory for EDC status.\n")); | ||
631 | return 0; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | dev = le16_to_cpup((void *)&buf[0]); | ||
636 | adr = le16_to_cpup((void *)&buf[2]); | ||
637 | opt = le16_to_cpup((void *)&buf[4]); | ||
638 | len = le16_to_cpup((void *)&buf[6]); | ||
639 | |||
640 | if (!(opt & BIT_0)) | ||
641 | if (len == 0 || len > DMA_POOL_SIZE) | ||
642 | return -EINVAL; | ||
643 | |||
644 | memset(ha->edc_data, 0, len); | ||
645 | rval = qla2x00_read_edc(vha, dev, adr, ha->edc_data_dma, | ||
646 | ha->edc_data, len, opt); | ||
647 | if (rval != QLA_SUCCESS) { | ||
648 | DEBUG2(qla_printk(KERN_INFO, ha, | ||
649 | "Unable to write EDC status (%x) %02x:%02x:%04x:%02x.\n", | ||
650 | rval, dev, adr, opt, len)); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | ha->edc_data_len = len; | ||
655 | |||
656 | return count; | ||
657 | } | ||
658 | |||
659 | static ssize_t | ||
660 | qla2x00_sysfs_read_edc_status(struct kobject *kobj, | ||
661 | struct bin_attribute *bin_attr, | ||
662 | char *buf, loff_t off, size_t count) | ||
663 | { | ||
664 | struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, | ||
665 | struct device, kobj))); | ||
666 | struct qla_hw_data *ha = vha->hw; | ||
667 | |||
668 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count == 0) | ||
669 | return 0; | ||
670 | |||
671 | if (!ha->edc_data || ha->edc_data_len == 0 || ha->edc_data_len > count) | ||
672 | return -EINVAL; | ||
673 | |||
674 | memcpy(buf, ha->edc_data, ha->edc_data_len); | ||
675 | |||
676 | return ha->edc_data_len; | ||
677 | } | ||
678 | |||
679 | static struct bin_attribute sysfs_edc_status_attr = { | ||
680 | .attr = { | ||
681 | .name = "edc_status", | ||
682 | .mode = S_IRUSR | S_IWUSR, | ||
683 | }, | ||
684 | .size = 0, | ||
685 | .write = qla2x00_sysfs_write_edc_status, | ||
686 | .read = qla2x00_sysfs_read_edc_status, | ||
687 | }; | ||
688 | |||
551 | static struct sysfs_entry { | 689 | static struct sysfs_entry { |
552 | char *name; | 690 | char *name; |
553 | struct bin_attribute *attr; | 691 | struct bin_attribute *attr; |
@@ -560,6 +698,8 @@ static struct sysfs_entry { | |||
560 | { "vpd", &sysfs_vpd_attr, 1 }, | 698 | { "vpd", &sysfs_vpd_attr, 1 }, |
561 | { "sfp", &sysfs_sfp_attr, 1 }, | 699 | { "sfp", &sysfs_sfp_attr, 1 }, |
562 | { "reset", &sysfs_reset_attr, }, | 700 | { "reset", &sysfs_reset_attr, }, |
701 | { "edc", &sysfs_edc_attr, 2 }, | ||
702 | { "edc_status", &sysfs_edc_status_attr, 2 }, | ||
563 | { NULL }, | 703 | { NULL }, |
564 | }; | 704 | }; |
565 | 705 | ||
@@ -573,6 +713,8 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) | |||
573 | for (iter = bin_file_entries; iter->name; iter++) { | 713 | for (iter = bin_file_entries; iter->name; iter++) { |
574 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) | 714 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) |
575 | continue; | 715 | continue; |
716 | if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) | ||
717 | continue; | ||
576 | 718 | ||
577 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, | 719 | ret = sysfs_create_bin_file(&host->shost_gendev.kobj, |
578 | iter->attr); | 720 | iter->attr); |
@@ -593,6 +735,8 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) | |||
593 | for (iter = bin_file_entries; iter->name; iter++) { | 735 | for (iter = bin_file_entries; iter->name; iter++) { |
594 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) | 736 | if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) |
595 | continue; | 737 | continue; |
738 | if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) | ||
739 | continue; | ||
596 | 740 | ||
597 | sysfs_remove_bin_file(&host->shost_gendev.kobj, | 741 | sysfs_remove_bin_file(&host->shost_gendev.kobj, |
598 | iter->attr); | 742 | iter->attr); |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 757e31d62146..5a55a20207ec 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
@@ -607,6 +607,7 @@ typedef struct { | |||
607 | #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ | 607 | #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ |
608 | #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ | 608 | #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ |
609 | #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ | 609 | #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ |
610 | #define MBC_WRITE_SFP 0x30 /* Write SFP Data. */ | ||
610 | #define MBC_READ_SFP 0x31 /* Read SFP Data. */ | 611 | #define MBC_READ_SFP 0x31 /* Read SFP Data. */ |
611 | #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ | 612 | #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ |
612 | #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ | 613 | #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ |
@@ -2387,6 +2388,10 @@ struct qla_hw_data { | |||
2387 | void *sfp_data; | 2388 | void *sfp_data; |
2388 | dma_addr_t sfp_data_dma; | 2389 | dma_addr_t sfp_data_dma; |
2389 | 2390 | ||
2391 | uint8_t *edc_data; | ||
2392 | dma_addr_t edc_data_dma; | ||
2393 | uint16_t edc_data_len; | ||
2394 | |||
2390 | struct task_struct *dpc_thread; | 2395 | struct task_struct *dpc_thread; |
2391 | uint8_t dpc_active; /* DPC routine is active */ | 2396 | uint8_t dpc_active; /* DPC routine is active */ |
2392 | 2397 | ||
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 41c3f41e6869..528913f6bed9 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -265,6 +265,14 @@ extern int | |||
265 | qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); | 265 | qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); |
266 | 266 | ||
267 | extern int | 267 | extern int |
268 | qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, | ||
269 | uint8_t *, uint16_t, uint16_t); | ||
270 | |||
271 | extern int | ||
272 | qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t, | ||
273 | uint8_t *, uint16_t, uint16_t); | ||
274 | |||
275 | extern int | ||
268 | qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); | 276 | qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); |
269 | 277 | ||
270 | extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); | 278 | extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); |
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 7af9bd73a10d..951537e30294 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c | |||
@@ -3347,3 +3347,81 @@ qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) | |||
3347 | 3347 | ||
3348 | return rval; | 3348 | return rval; |
3349 | } | 3349 | } |
3350 | |||
3351 | int | ||
3352 | qla2x00_read_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, | ||
3353 | dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) | ||
3354 | { | ||
3355 | int rval; | ||
3356 | mbx_cmd_t mc; | ||
3357 | mbx_cmd_t *mcp = &mc; | ||
3358 | |||
3359 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
3360 | |||
3361 | mcp->mb[0] = MBC_READ_SFP; | ||
3362 | mcp->mb[1] = dev; | ||
3363 | mcp->mb[2] = MSW(sfp_dma); | ||
3364 | mcp->mb[3] = LSW(sfp_dma); | ||
3365 | mcp->mb[6] = MSW(MSD(sfp_dma)); | ||
3366 | mcp->mb[7] = LSW(MSD(sfp_dma)); | ||
3367 | mcp->mb[8] = len; | ||
3368 | mcp->mb[9] = adr; | ||
3369 | mcp->mb[10] = opt; | ||
3370 | mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; | ||
3371 | mcp->in_mb = MBX_0; | ||
3372 | mcp->tov = MBX_TOV_SECONDS; | ||
3373 | mcp->flags = 0; | ||
3374 | rval = qla2x00_mailbox_command(vha, mcp); | ||
3375 | |||
3376 | if (opt & BIT_0) | ||
3377 | if (sfp) | ||
3378 | *sfp = mcp->mb[8]; | ||
3379 | |||
3380 | if (rval != QLA_SUCCESS) { | ||
3381 | DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, | ||
3382 | vha->host_no, rval, mcp->mb[0])); | ||
3383 | } else { | ||
3384 | DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); | ||
3385 | } | ||
3386 | |||
3387 | return rval; | ||
3388 | } | ||
3389 | |||
3390 | int | ||
3391 | qla2x00_write_edc(scsi_qla_host_t *vha, uint16_t dev, uint16_t adr, | ||
3392 | dma_addr_t sfp_dma, uint8_t *sfp, uint16_t len, uint16_t opt) | ||
3393 | { | ||
3394 | int rval; | ||
3395 | mbx_cmd_t mc; | ||
3396 | mbx_cmd_t *mcp = &mc; | ||
3397 | |||
3398 | DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); | ||
3399 | |||
3400 | if (opt & BIT_0) | ||
3401 | if (sfp) | ||
3402 | len = *sfp; | ||
3403 | |||
3404 | mcp->mb[0] = MBC_WRITE_SFP; | ||
3405 | mcp->mb[1] = dev; | ||
3406 | mcp->mb[2] = MSW(sfp_dma); | ||
3407 | mcp->mb[3] = LSW(sfp_dma); | ||
3408 | mcp->mb[6] = MSW(MSD(sfp_dma)); | ||
3409 | mcp->mb[7] = LSW(MSD(sfp_dma)); | ||
3410 | mcp->mb[8] = len; | ||
3411 | mcp->mb[9] = adr; | ||
3412 | mcp->mb[10] = opt; | ||
3413 | mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; | ||
3414 | mcp->in_mb = MBX_0; | ||
3415 | mcp->tov = MBX_TOV_SECONDS; | ||
3416 | mcp->flags = 0; | ||
3417 | rval = qla2x00_mailbox_command(vha, mcp); | ||
3418 | |||
3419 | if (rval != QLA_SUCCESS) { | ||
3420 | DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, | ||
3421 | vha->host_no, rval, mcp->mb[0])); | ||
3422 | } else { | ||
3423 | DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no)); | ||
3424 | } | ||
3425 | |||
3426 | return rval; | ||
3427 | } | ||
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ba3309f85560..9bb4b2ed6608 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -2337,6 +2337,9 @@ qla2x00_mem_free(struct qla_hw_data *ha) | |||
2337 | if (ha->sfp_data) | 2337 | if (ha->sfp_data) |
2338 | dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); | 2338 | dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); |
2339 | 2339 | ||
2340 | if (ha->edc_data) | ||
2341 | dma_pool_free(ha->s_dma_pool, ha->edc_data, ha->edc_data_dma); | ||
2342 | |||
2340 | if (ha->ms_iocb) | 2343 | if (ha->ms_iocb) |
2341 | dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); | 2344 | dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); |
2342 | 2345 | ||