diff options
| -rw-r--r-- | drivers/scsi/qla1280.c | 161 |
1 files changed, 109 insertions, 52 deletions
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 49ac4148493b..66e2dd43008a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c | |||
| @@ -17,9 +17,11 @@ | |||
| 17 | * General Public License for more details. | 17 | * General Public License for more details. |
| 18 | * | 18 | * |
| 19 | ******************************************************************************/ | 19 | ******************************************************************************/ |
| 20 | #define QLA1280_VERSION "3.27" | 20 | #define QLA1280_VERSION "3.27.1" |
| 21 | /***************************************************************************** | 21 | /***************************************************************************** |
| 22 | Revision History: | 22 | Revision History: |
| 23 | Rev 3.27.1, February 8, 2010, Michael Reed | ||
| 24 | - Retain firmware image for error recovery. | ||
| 23 | Rev 3.27, February 10, 2009, Michael Reed | 25 | Rev 3.27, February 10, 2009, Michael Reed |
| 24 | - General code cleanup. | 26 | - General code cleanup. |
| 25 | - Improve error recovery. | 27 | - Improve error recovery. |
| @@ -538,9 +540,9 @@ __setup("qla1280=", qla1280_setup); | |||
| 538 | /*****************************************/ | 540 | /*****************************************/ |
| 539 | 541 | ||
| 540 | struct qla_boards { | 542 | struct qla_boards { |
| 541 | unsigned char name[9]; /* Board ID String */ | 543 | char *name; /* Board ID String */ |
| 542 | int numPorts; /* Number of SCSI ports */ | 544 | int numPorts; /* Number of SCSI ports */ |
| 543 | char *fwname; /* firmware name */ | 545 | int fw_index; /* index into qla1280_fw_tbl for firmware */ |
| 544 | }; | 546 | }; |
| 545 | 547 | ||
| 546 | /* NOTE: the last argument in each entry is used to index ql1280_board_tbl */ | 548 | /* NOTE: the last argument in each entry is used to index ql1280_board_tbl */ |
| @@ -561,15 +563,30 @@ static struct pci_device_id qla1280_pci_tbl[] = { | |||
| 561 | }; | 563 | }; |
| 562 | MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); | 564 | MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); |
| 563 | 565 | ||
| 566 | DEFINE_MUTEX(qla1280_firmware_mutex); | ||
| 567 | |||
| 568 | struct qla_fw { | ||
| 569 | char *fwname; | ||
| 570 | const struct firmware *fw; | ||
| 571 | }; | ||
| 572 | |||
| 573 | #define QL_NUM_FW_IMAGES 3 | ||
| 574 | |||
| 575 | struct qla_fw qla1280_fw_tbl[QL_NUM_FW_IMAGES] = { | ||
| 576 | {"qlogic/1040.bin", NULL}, /* image 0 */ | ||
| 577 | {"qlogic/1280.bin", NULL}, /* image 1 */ | ||
| 578 | {"qlogic/12160.bin", NULL}, /* image 2 */ | ||
| 579 | }; | ||
| 580 | |||
| 581 | /* NOTE: Order of boards in this table must match order in qla1280_pci_tbl */ | ||
| 564 | static struct qla_boards ql1280_board_tbl[] = { | 582 | static struct qla_boards ql1280_board_tbl[] = { |
| 565 | /* Name , Number of ports, FW details */ | 583 | {.name = "QLA12160", .numPorts = 2, .fw_index = 2}, |
| 566 | {"QLA12160", 2, "qlogic/12160.bin"}, | 584 | {.name = "QLA1040" , .numPorts = 1, .fw_index = 0}, |
| 567 | {"QLA1040", 1, "qlogic/1040.bin"}, | 585 | {.name = "QLA1080" , .numPorts = 1, .fw_index = 1}, |
| 568 | {"QLA1080", 1, "qlogic/1280.bin"}, | 586 | {.name = "QLA1240" , .numPorts = 2, .fw_index = 1}, |
| 569 | {"QLA1240", 2, "qlogic/1280.bin"}, | 587 | {.name = "QLA1280" , .numPorts = 2, .fw_index = 1}, |
| 570 | {"QLA1280", 2, "qlogic/1280.bin"}, | 588 | {.name = "QLA10160", .numPorts = 1, .fw_index = 2}, |
| 571 | {"QLA10160", 1, "qlogic/12160.bin"}, | 589 | {.name = " ", .numPorts = 0, .fw_index = -1}, |
| 572 | {" ", 0, " "}, | ||
| 573 | }; | 590 | }; |
| 574 | 591 | ||
| 575 | static int qla1280_verbose = 1; | 592 | static int qla1280_verbose = 1; |
| @@ -1512,6 +1529,63 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) | |||
| 1512 | } | 1529 | } |
| 1513 | 1530 | ||
| 1514 | /* | 1531 | /* |
| 1532 | * qla1280_request_firmware | ||
| 1533 | * Acquire firmware for chip. Retain in memory | ||
| 1534 | * for error recovery. | ||
| 1535 | * | ||
| 1536 | * Input: | ||
| 1537 | * ha = adapter block pointer. | ||
| 1538 | * | ||
| 1539 | * Returns: | ||
| 1540 | * Pointer to firmware image or an error code | ||
| 1541 | * cast to pointer via ERR_PTR(). | ||
| 1542 | */ | ||
| 1543 | static const struct firmware * | ||
| 1544 | qla1280_request_firmware(struct scsi_qla_host *ha) | ||
| 1545 | { | ||
| 1546 | const struct firmware *fw; | ||
| 1547 | int err; | ||
| 1548 | int index; | ||
| 1549 | char *fwname; | ||
| 1550 | |||
| 1551 | spin_unlock_irq(ha->host->host_lock); | ||
| 1552 | mutex_lock(&qla1280_firmware_mutex); | ||
| 1553 | |||
| 1554 | index = ql1280_board_tbl[ha->devnum].fw_index; | ||
| 1555 | fw = qla1280_fw_tbl[index].fw; | ||
| 1556 | if (fw) | ||
| 1557 | goto out; | ||
| 1558 | |||
| 1559 | fwname = qla1280_fw_tbl[index].fwname; | ||
| 1560 | err = request_firmware(&fw, fwname, &ha->pdev->dev); | ||
| 1561 | |||
| 1562 | if (err) { | ||
| 1563 | printk(KERN_ERR "Failed to load image \"%s\" err %d\n", | ||
| 1564 | fwname, err); | ||
| 1565 | fw = ERR_PTR(err); | ||
| 1566 | goto unlock; | ||
| 1567 | } | ||
| 1568 | if ((fw->size % 2) || (fw->size < 6)) { | ||
| 1569 | printk(KERN_ERR "Invalid firmware length %zu in image \"%s\"\n", | ||
| 1570 | fw->size, fwname); | ||
| 1571 | release_firmware(fw); | ||
| 1572 | fw = ERR_PTR(-EINVAL); | ||
| 1573 | goto unlock; | ||
| 1574 | } | ||
| 1575 | |||
| 1576 | qla1280_fw_tbl[index].fw = fw; | ||
| 1577 | |||
| 1578 | out: | ||
| 1579 | ha->fwver1 = fw->data[0]; | ||
| 1580 | ha->fwver2 = fw->data[1]; | ||
| 1581 | ha->fwver3 = fw->data[2]; | ||
| 1582 | unlock: | ||
| 1583 | mutex_unlock(&qla1280_firmware_mutex); | ||
| 1584 | spin_lock_irq(ha->host->host_lock); | ||
| 1585 | return fw; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | /* | ||
| 1515 | * Chip diagnostics | 1589 | * Chip diagnostics |
| 1516 | * Test chip for proper operation. | 1590 | * Test chip for proper operation. |
| 1517 | * | 1591 | * |
| @@ -1634,30 +1708,18 @@ qla1280_chip_diag(struct scsi_qla_host *ha) | |||
| 1634 | static int | 1708 | static int |
| 1635 | qla1280_load_firmware_pio(struct scsi_qla_host *ha) | 1709 | qla1280_load_firmware_pio(struct scsi_qla_host *ha) |
| 1636 | { | 1710 | { |
| 1711 | /* enter with host_lock acquired */ | ||
| 1712 | |||
| 1637 | const struct firmware *fw; | 1713 | const struct firmware *fw; |
| 1638 | const __le16 *fw_data; | 1714 | const __le16 *fw_data; |
| 1639 | uint16_t risc_address, risc_code_size; | 1715 | uint16_t risc_address, risc_code_size; |
| 1640 | uint16_t mb[MAILBOX_REGISTER_COUNT], i; | 1716 | uint16_t mb[MAILBOX_REGISTER_COUNT], i; |
| 1641 | int err; | 1717 | int err = 0; |
| 1718 | |||
| 1719 | fw = qla1280_request_firmware(ha); | ||
| 1720 | if (IS_ERR(fw)) | ||
| 1721 | return PTR_ERR(fw); | ||
| 1642 | 1722 | ||
| 1643 | spin_unlock_irq(ha->host->host_lock); | ||
| 1644 | err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, | ||
| 1645 | &ha->pdev->dev); | ||
| 1646 | spin_lock_irq(ha->host->host_lock); | ||
| 1647 | if (err) { | ||
| 1648 | printk(KERN_ERR "Failed to load image \"%s\" err %d\n", | ||
| 1649 | ql1280_board_tbl[ha->devnum].fwname, err); | ||
| 1650 | return err; | ||
| 1651 | } | ||
| 1652 | if ((fw->size % 2) || (fw->size < 6)) { | ||
| 1653 | printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", | ||
| 1654 | fw->size, ql1280_board_tbl[ha->devnum].fwname); | ||
| 1655 | err = -EINVAL; | ||
| 1656 | goto out; | ||
| 1657 | } | ||
| 1658 | ha->fwver1 = fw->data[0]; | ||
| 1659 | ha->fwver2 = fw->data[1]; | ||
| 1660 | ha->fwver3 = fw->data[2]; | ||
| 1661 | fw_data = (const __le16 *)&fw->data[0]; | 1723 | fw_data = (const __le16 *)&fw->data[0]; |
| 1662 | ha->fwstart = __le16_to_cpu(fw_data[2]); | 1724 | ha->fwstart = __le16_to_cpu(fw_data[2]); |
| 1663 | 1725 | ||
| @@ -1675,11 +1737,10 @@ qla1280_load_firmware_pio(struct scsi_qla_host *ha) | |||
| 1675 | if (err) { | 1737 | if (err) { |
| 1676 | printk(KERN_ERR "scsi(%li): Failed to load firmware\n", | 1738 | printk(KERN_ERR "scsi(%li): Failed to load firmware\n", |
| 1677 | ha->host_no); | 1739 | ha->host_no); |
| 1678 | goto out; | 1740 | break; |
| 1679 | } | 1741 | } |
| 1680 | } | 1742 | } |
| 1681 | out: | 1743 | |
| 1682 | release_firmware(fw); | ||
| 1683 | return err; | 1744 | return err; |
| 1684 | } | 1745 | } |
| 1685 | 1746 | ||
| @@ -1687,6 +1748,7 @@ out: | |||
| 1687 | static int | 1748 | static int |
| 1688 | qla1280_load_firmware_dma(struct scsi_qla_host *ha) | 1749 | qla1280_load_firmware_dma(struct scsi_qla_host *ha) |
| 1689 | { | 1750 | { |
| 1751 | /* enter with host_lock acquired */ | ||
| 1690 | const struct firmware *fw; | 1752 | const struct firmware *fw; |
| 1691 | const __le16 *fw_data; | 1753 | const __le16 *fw_data; |
| 1692 | uint16_t risc_address, risc_code_size; | 1754 | uint16_t risc_address, risc_code_size; |
| @@ -1701,24 +1763,10 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) | |||
| 1701 | return -ENOMEM; | 1763 | return -ENOMEM; |
| 1702 | #endif | 1764 | #endif |
| 1703 | 1765 | ||
| 1704 | spin_unlock_irq(ha->host->host_lock); | 1766 | fw = qla1280_request_firmware(ha); |
| 1705 | err = request_firmware(&fw, ql1280_board_tbl[ha->devnum].fwname, | 1767 | if (IS_ERR(fw)) |
| 1706 | &ha->pdev->dev); | 1768 | return PTR_ERR(fw); |
| 1707 | spin_lock_irq(ha->host->host_lock); | 1769 | |
| 1708 | if (err) { | ||
| 1709 | printk(KERN_ERR "Failed to load image \"%s\" err %d\n", | ||
| 1710 | ql1280_board_tbl[ha->devnum].fwname, err); | ||
| 1711 | return err; | ||
| 1712 | } | ||
| 1713 | if ((fw->size % 2) || (fw->size < 6)) { | ||
| 1714 | printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", | ||
| 1715 | fw->size, ql1280_board_tbl[ha->devnum].fwname); | ||
| 1716 | err = -EINVAL; | ||
| 1717 | goto out; | ||
| 1718 | } | ||
| 1719 | ha->fwver1 = fw->data[0]; | ||
| 1720 | ha->fwver2 = fw->data[1]; | ||
| 1721 | ha->fwver3 = fw->data[2]; | ||
| 1722 | fw_data = (const __le16 *)&fw->data[0]; | 1770 | fw_data = (const __le16 *)&fw->data[0]; |
| 1723 | ha->fwstart = __le16_to_cpu(fw_data[2]); | 1771 | ha->fwstart = __le16_to_cpu(fw_data[2]); |
| 1724 | 1772 | ||
| @@ -1803,7 +1851,6 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) | |||
| 1803 | #if DUMP_IT_BACK | 1851 | #if DUMP_IT_BACK |
| 1804 | pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); | 1852 | pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); |
| 1805 | #endif | 1853 | #endif |
| 1806 | release_firmware(fw); | ||
| 1807 | return err; | 1854 | return err; |
| 1808 | } | 1855 | } |
| 1809 | 1856 | ||
| @@ -1842,6 +1889,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) | |||
| 1842 | static int | 1889 | static int |
| 1843 | qla1280_load_firmware(struct scsi_qla_host *ha) | 1890 | qla1280_load_firmware(struct scsi_qla_host *ha) |
| 1844 | { | 1891 | { |
| 1892 | /* enter with host_lock taken */ | ||
| 1845 | int err; | 1893 | int err; |
| 1846 | 1894 | ||
| 1847 | err = qla1280_chip_diag(ha); | 1895 | err = qla1280_chip_diag(ha); |
| @@ -4420,7 +4468,16 @@ qla1280_init(void) | |||
| 4420 | static void __exit | 4468 | static void __exit |
| 4421 | qla1280_exit(void) | 4469 | qla1280_exit(void) |
| 4422 | { | 4470 | { |
| 4471 | int i; | ||
| 4472 | |||
| 4423 | pci_unregister_driver(&qla1280_pci_driver); | 4473 | pci_unregister_driver(&qla1280_pci_driver); |
| 4474 | /* release any allocated firmware images */ | ||
| 4475 | for (i = 0; i < QL_NUM_FW_IMAGES; i++) { | ||
| 4476 | if (qla1280_fw_tbl[i].fw) { | ||
| 4477 | release_firmware(qla1280_fw_tbl[i].fw); | ||
| 4478 | qla1280_fw_tbl[i].fw = NULL; | ||
| 4479 | } | ||
| 4480 | } | ||
| 4424 | } | 4481 | } |
| 4425 | 4482 | ||
| 4426 | module_init(qla1280_init); | 4483 | module_init(qla1280_init); |
