aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Carnuccio <joe.carnuccio@qlogic.com>2009-03-24 12:08:12 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-04-03 10:22:51 -0400
commitad0ecd61f4ad3260ca8f7216765ddbb1a10677ea (patch)
tree4a228bd11305a1c07647b948e571542ac9b9389c
parentfbcbb5d0cf69ba8b59028ec3c5b9f9ff04409b88 (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>
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c144
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h8
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c78
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c3
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
551static ssize_t
552qla2x00_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
600static 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
609static ssize_t
610qla2x00_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
659static ssize_t
660qla2x00_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
679static 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
551static struct sysfs_entry { 689static 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
265qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); 265qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
266 266
267extern int 267extern int
268qla2x00_read_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
269 uint8_t *, uint16_t, uint16_t);
270
271extern int
272qla2x00_write_edc(scsi_qla_host_t *, uint16_t, uint16_t, dma_addr_t,
273 uint8_t *, uint16_t, uint16_t);
274
275extern int
268qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); 276qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
269 277
270extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); 278extern 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
3351int
3352qla2x00_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
3390int
3391qla2x00_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