[SCSI] qla2xxx: Add full firmware(-request) hotplug support for all ISPs.
Transition driver to exclusively use the request_firmware() interfaces to retrieve firmware-blobs from user-space. This will be the default behaviour going forward until the embedded firmware-binary images are removed from the upstream kernel. Upon request, the driver caches the firmware image until the driver is unloaded. NOTE: The option is present to allow the user to continue to use the firmware-loader modules, but, should be considered deprecated. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Rejections fixed up and Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
parent
26a68019c8
commit
5433383ef3
7 changed files with 348 additions and 98 deletions
|
@ -1,55 +1,70 @@
|
|||
config SCSI_QLA2XXX
|
||||
tristate
|
||||
default (SCSI && PCI)
|
||||
depends on SCSI && PCI
|
||||
tristate "QLogic QLA2XXX Fibre Channel Support"
|
||||
depends on PCI && SCSI
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
---help---
|
||||
This qla2xxx driver supports all QLogic Fibre Channel
|
||||
PCI and PCIe host adapters.
|
||||
|
||||
By default, firmware for the ISP parts will be loaded
|
||||
via the Firmware Loader interface.
|
||||
|
||||
ISP Firmware Filename
|
||||
---------- -----------------
|
||||
21xx ql2100_fw.bin
|
||||
22xx ql2200_fw.bin
|
||||
2300, 2312 ql2300_fw.bin
|
||||
2322 ql2322_fw.bin
|
||||
6312, 6322 ql6312_fw.bin
|
||||
24xx ql2400_fw.bin
|
||||
|
||||
Upon request, the driver caches the firmware image until
|
||||
the driver is unloaded.
|
||||
|
||||
NOTE: The original method of building firmware-loader
|
||||
modules has been deprecated as the firmware-images will
|
||||
be removed from the kernel sources.
|
||||
|
||||
config SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
bool " Use firmware-loader modules (DEPRECATED)"
|
||||
depends on SCSI_QLA2XXX
|
||||
|
||||
config SCSI_QLA21XX
|
||||
tristate "QLogic ISP2100 host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP2100 firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 21xx (ISP2100) host adapter family.
|
||||
|
||||
config SCSI_QLA22XX
|
||||
tristate "QLogic ISP2200 host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP2200 firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 22xx (ISP2200) host adapter family.
|
||||
|
||||
config SCSI_QLA2300
|
||||
tristate "QLogic ISP2300 host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP2300 firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 2300 (ISP2300 and ISP2312) host
|
||||
adapter family.
|
||||
|
||||
config SCSI_QLA2322
|
||||
tristate "QLogic ISP2322 host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP2322 firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 2322 (ISP2322) host adapter family.
|
||||
|
||||
config SCSI_QLA6312
|
||||
tristate "QLogic ISP63xx host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP63xx firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 63xx (ISP6312 and ISP6322) host
|
||||
adapter family.
|
||||
|
||||
config SCSI_QLA24XX
|
||||
tristate "QLogic ISP24xx host adapter family support"
|
||||
depends on SCSI_QLA2XXX
|
||||
select SCSI_FC_ATTRS
|
||||
select FW_LOADER
|
||||
tristate " Build QLogic ISP24xx firmware-module"
|
||||
depends on SCSI_QLA2XXX_EMBEDDED_FIRMWARE
|
||||
---help---
|
||||
This driver supports the QLogic 24xx (ISP2422 and ISP2432) host
|
||||
adapter family.
|
||||
|
|
|
@ -3,6 +3,8 @@ EXTRA_CFLAGS += -DUNIQUE_FW_NAME
|
|||
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
|
||||
qla_dbg.o qla_sup.o qla_rscn.o qla_attr.o
|
||||
|
||||
obj-$(CONFIG_SCSI_QLA2XXX) += qla2xxx.o
|
||||
|
||||
qla2100-y := ql2100.o ql2100_fw.o
|
||||
qla2200-y := ql2200.o ql2200_fw.o
|
||||
qla2300-y := ql2300.o ql2300_fw.o
|
||||
|
|
|
@ -232,7 +232,7 @@ static ssize_t
|
|||
qla2x00_isp_name_show(struct class_device *cdev, char *buf)
|
||||
{
|
||||
scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev));
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name);
|
||||
return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
|
||||
#if defined(CONFIG_SCSI_QLA21XX) || defined(CONFIG_SCSI_QLA21XX_MODULE)
|
||||
#define IS_QLA2100(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2100)
|
||||
#else
|
||||
|
@ -79,9 +81,23 @@
|
|||
#define IS_QLA2522(ha) 0
|
||||
#endif
|
||||
|
||||
#else /* !defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE) */
|
||||
|
||||
#define IS_QLA2100(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2100)
|
||||
#define IS_QLA2200(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2200)
|
||||
#define IS_QLA2300(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2300)
|
||||
#define IS_QLA2312(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2312)
|
||||
#define IS_QLA2322(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2322)
|
||||
#define IS_QLA6312(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6312)
|
||||
#define IS_QLA6322(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6322)
|
||||
#define IS_QLA2422(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422)
|
||||
#define IS_QLA2432(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432)
|
||||
#define IS_QLA2512(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2512)
|
||||
#define IS_QLA2522(ha) ((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2522)
|
||||
#endif
|
||||
|
||||
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
|
||||
IS_QLA6312(ha) || IS_QLA6322(ha))
|
||||
|
||||
#define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha))
|
||||
#define IS_QLA25XX(ha) (IS_QLA2512(ha) || IS_QLA2522(ha))
|
||||
|
||||
|
@ -2124,6 +2140,12 @@ struct qla_board_info {
|
|||
struct scsi_host_template *sht;
|
||||
};
|
||||
|
||||
struct fw_blob {
|
||||
char *name;
|
||||
uint32_t segs[4];
|
||||
const struct firmware *fw;
|
||||
};
|
||||
|
||||
/* Return data from MBC_GET_ID_LIST call. */
|
||||
struct gid_list_info {
|
||||
uint8_t al_pa;
|
||||
|
|
|
@ -33,8 +33,8 @@ extern int qla24xx_nvram_config(struct scsi_qla_host *);
|
|||
extern void qla2x00_update_fw_options(struct scsi_qla_host *);
|
||||
extern void qla24xx_update_fw_options(scsi_qla_host_t *);
|
||||
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
|
||||
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla24xx_load_risc_hotplug(scsi_qla_host_t *, uint32_t *);
|
||||
|
||||
extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t);
|
||||
|
||||
|
@ -76,6 +76,8 @@ extern void qla2x00_blink_led(scsi_qla_host_t *);
|
|||
|
||||
extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
|
||||
|
||||
extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_iocb.c source file.
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <scsi/scsi_transport_fc.h>
|
||||
|
||||
#include "qla_devtbl.h"
|
||||
|
@ -3484,17 +3483,16 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
|
|||
return (rval);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
|
||||
|
||||
int
|
||||
qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
uint16_t cnt;
|
||||
uint16_t *risc_code;
|
||||
unsigned long risc_address;
|
||||
unsigned long risc_code_size;
|
||||
int num;
|
||||
int i;
|
||||
uint16_t *req_ring;
|
||||
int rval, num, i;
|
||||
uint32_t cnt;
|
||||
uint16_t *risc_code;
|
||||
uint32_t risc_addr, risc_size;
|
||||
uint16_t *req_ring;
|
||||
struct qla_fw_info *fw_iter;
|
||||
|
||||
rval = QLA_SUCCESS;
|
||||
|
@ -3504,37 +3502,29 @@ qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
*srisc_addr = *ha->brd_info->fw_info->fwstart;
|
||||
while (fw_iter->addressing != FW_INFO_ADDR_NOMORE) {
|
||||
risc_code = fw_iter->fwcode;
|
||||
risc_code_size = *fw_iter->fwlen;
|
||||
|
||||
if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) {
|
||||
risc_address = *fw_iter->fwstart;
|
||||
} else {
|
||||
/* Extended address */
|
||||
risc_address = *fw_iter->lfwstart;
|
||||
}
|
||||
risc_size = *fw_iter->fwlen;
|
||||
if (fw_iter->addressing == FW_INFO_ADDR_NORMAL)
|
||||
risc_addr = *fw_iter->fwstart;
|
||||
else
|
||||
risc_addr = *fw_iter->lfwstart;
|
||||
|
||||
num = 0;
|
||||
rval = 0;
|
||||
while (risc_code_size > 0 && !rval) {
|
||||
while (risc_size > 0 && !rval) {
|
||||
cnt = (uint16_t)(ha->fw_transfer_size >> 1);
|
||||
if (cnt > risc_code_size)
|
||||
cnt = risc_code_size;
|
||||
if (cnt > risc_size)
|
||||
cnt = risc_size;
|
||||
|
||||
DEBUG7(printk("scsi(%ld): Loading risc segment@ "
|
||||
"addr %p, number of bytes 0x%x, offset 0x%lx.\n",
|
||||
ha->host_no, risc_code, cnt, risc_address));
|
||||
ha->host_no, risc_code, cnt, risc_addr));
|
||||
|
||||
req_ring = (uint16_t *)ha->request_ring;
|
||||
for (i = 0; i < cnt; i++)
|
||||
req_ring[i] = cpu_to_le16(risc_code[i]);
|
||||
|
||||
if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) {
|
||||
rval = qla2x00_load_ram(ha, ha->request_dma,
|
||||
risc_address, cnt);
|
||||
} else {
|
||||
rval = qla2x00_load_ram_ext(ha,
|
||||
ha->request_dma, risc_address, cnt);
|
||||
}
|
||||
rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
|
||||
cnt);
|
||||
if (rval) {
|
||||
DEBUG(printk("scsi(%ld): [ERROR] Failed to "
|
||||
"load segment %d of firmware\n",
|
||||
|
@ -3548,16 +3538,15 @@ qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
}
|
||||
|
||||
risc_code += cnt;
|
||||
risc_address += cnt;
|
||||
risc_code_size -= cnt;
|
||||
risc_addr += cnt;
|
||||
risc_size -= cnt;
|
||||
num++;
|
||||
}
|
||||
|
||||
/* Next firmware sequence */
|
||||
fw_iter++;
|
||||
}
|
||||
|
||||
return (rval);
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -3642,8 +3631,108 @@ qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
return rval;
|
||||
}
|
||||
|
||||
#else /* !defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE) */
|
||||
|
||||
int
|
||||
qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
||||
qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
int i, fragment;
|
||||
uint16_t *wcode, *fwcode;
|
||||
uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
|
||||
struct fw_blob *blob;
|
||||
|
||||
/* Load firmware blob. */
|
||||
blob = qla2x00_request_firmware(ha);
|
||||
if (!blob) {
|
||||
qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rval = QLA_SUCCESS;
|
||||
|
||||
wcode = (uint16_t *)ha->request_ring;
|
||||
*srisc_addr = 0;
|
||||
fwcode = (uint16_t *)blob->fw->data;
|
||||
fwclen = 0;
|
||||
|
||||
/* Validate firmware image by checking version. */
|
||||
if (blob->fw->size < 8 * sizeof(uint16_t)) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of firmware image (%Zd)!\n",
|
||||
blob->fw->size);
|
||||
goto fail_fw_integrity;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
wcode[i] = be16_to_cpu(fwcode[i + 4]);
|
||||
if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
|
||||
wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
|
||||
wcode[2] == 0 && wcode[3] == 0)) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of firmware image!\n");
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Firmware data: %04x %04x %04x %04x!\n", wcode[0],
|
||||
wcode[1], wcode[2], wcode[3]);
|
||||
goto fail_fw_integrity;
|
||||
}
|
||||
|
||||
seg = blob->segs;
|
||||
while (*seg && rval == QLA_SUCCESS) {
|
||||
risc_addr = *seg;
|
||||
*srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
|
||||
risc_size = be16_to_cpu(fwcode[3]);
|
||||
|
||||
/* Validate firmware image size. */
|
||||
fwclen += risc_size * sizeof(uint16_t);
|
||||
if (blob->fw->size < fwclen) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of firmware image "
|
||||
"(%Zd)!\n", blob->fw->size);
|
||||
goto fail_fw_integrity;
|
||||
}
|
||||
|
||||
fragment = 0;
|
||||
while (risc_size > 0 && rval == QLA_SUCCESS) {
|
||||
wlen = (uint16_t)(ha->fw_transfer_size >> 1);
|
||||
if (wlen > risc_size)
|
||||
wlen = risc_size;
|
||||
|
||||
DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
|
||||
"addr %x, number of words 0x%x.\n", ha->host_no,
|
||||
risc_addr, wlen));
|
||||
|
||||
for (i = 0; i < wlen; i++)
|
||||
wcode[i] = swab16(fwcode[i]);
|
||||
|
||||
rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
|
||||
wlen);
|
||||
if (rval) {
|
||||
DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
|
||||
"segment %d of firmware\n", ha->host_no,
|
||||
fragment));
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"[ERROR] Failed to load segment %d of "
|
||||
"firmware\n", fragment);
|
||||
break;
|
||||
}
|
||||
|
||||
fwcode += wlen;
|
||||
risc_addr += wlen;
|
||||
risc_size -= wlen;
|
||||
fragment++;
|
||||
}
|
||||
|
||||
/* Next segment. */
|
||||
seg++;
|
||||
}
|
||||
return rval;
|
||||
|
||||
fail_fw_integrity:
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
int
|
||||
qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
int segments, fragment;
|
||||
|
@ -3651,14 +3740,13 @@ qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
uint32_t risc_addr;
|
||||
uint32_t risc_size;
|
||||
uint32_t i;
|
||||
const struct firmware *fw_entry;
|
||||
struct fw_blob *blob;
|
||||
uint32_t *fwcode, fwclen;
|
||||
|
||||
if (request_firmware(&fw_entry, ha->brd_info->fw_fname,
|
||||
&ha->pdev->dev)) {
|
||||
qla_printk(KERN_ERR, ha,
|
||||
"Firmware image file not available: '%s'\n",
|
||||
ha->brd_info->fw_fname);
|
||||
/* Load firmware blob. */
|
||||
blob = qla2x00_request_firmware(ha);
|
||||
if (!blob) {
|
||||
qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
|
@ -3667,14 +3755,14 @@ qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
segments = FA_RISC_CODE_SEGMENTS;
|
||||
dcode = (uint32_t *)ha->request_ring;
|
||||
*srisc_addr = 0;
|
||||
fwcode = (uint32_t *)fw_entry->data;
|
||||
fwcode = (uint32_t *)blob->fw->data;
|
||||
fwclen = 0;
|
||||
|
||||
/* Validate firmware image by checking version. */
|
||||
if (fw_entry->size < 8 * sizeof(uint32_t)) {
|
||||
if (blob->fw->size < 8 * sizeof(uint32_t)) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of flash firmware image "
|
||||
"(%Zd)!\n", fw_entry->size);
|
||||
"Unable to verify integrity of firmware image (%Zd)!\n",
|
||||
blob->fw->size);
|
||||
goto fail_fw_integrity;
|
||||
}
|
||||
for (i = 0; i < 4; i++)
|
||||
|
@ -3684,7 +3772,7 @@ qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
(dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
|
||||
dcode[3] == 0)) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of flash firmware image!\n");
|
||||
"Unable to verify integrity of firmware image!\n");
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Firmware data: %08x %08x %08x %08x!\n", dcode[0],
|
||||
dcode[1], dcode[2], dcode[3]);
|
||||
|
@ -3698,10 +3786,11 @@ qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
|
||||
/* Validate firmware image size. */
|
||||
fwclen += risc_size * sizeof(uint32_t);
|
||||
if (fw_entry->size < fwclen) {
|
||||
if (blob->fw->size < fwclen) {
|
||||
qla_printk(KERN_WARNING, ha,
|
||||
"Unable to verify integrity of flash firmware "
|
||||
"image (%Zd)!\n", fw_entry->size);
|
||||
"Unable to verify integrity of firmware image "
|
||||
"(%Zd)!\n", blob->fw->size);
|
||||
|
||||
goto fail_fw_integrity;
|
||||
}
|
||||
|
||||
|
@ -3739,13 +3828,9 @@ qla24xx_load_risc_hotplug(scsi_qla_host_t *ha, uint32_t *srisc_addr)
|
|||
/* Next segment. */
|
||||
segments--;
|
||||
}
|
||||
|
||||
release_firmware(fw_entry);
|
||||
return rval;
|
||||
|
||||
fail_fw_integrity:
|
||||
|
||||
release_firmware(fw_entry);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -54,11 +54,6 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
|
|||
MODULE_PARM_DESC(ql2xloginretrycount,
|
||||
"Specify an alternate value for the NVRAM login retry count.");
|
||||
|
||||
int ql2xfwloadbin=1;
|
||||
module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR);
|
||||
MODULE_PARM_DESC(ql2xfwloadbin,
|
||||
"Load ISP2xxx firmware image via hotplug.");
|
||||
|
||||
static void qla2x00_free_device(scsi_qla_host_t *);
|
||||
|
||||
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
|
||||
|
@ -1261,12 +1256,16 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
|
|||
char pci_info[20];
|
||||
char fw_str[30];
|
||||
fc_port_t *fcport;
|
||||
struct scsi_host_template *sht;
|
||||
|
||||
if (pci_enable_device(pdev))
|
||||
goto probe_out;
|
||||
|
||||
host = scsi_host_alloc(brd_info->sht ? brd_info->sht:
|
||||
&qla2x00_driver_template, sizeof(scsi_qla_host_t));
|
||||
sht = &qla2x00_driver_template;
|
||||
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432)
|
||||
sht = &qla24xx_driver_template;
|
||||
host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
|
||||
if (host == NULL) {
|
||||
printk(KERN_WARNING
|
||||
"qla2xxx: Couldn't allocate host from scsi layer!\n");
|
||||
|
@ -1291,8 +1290,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
|
|||
goto probe_failed;
|
||||
|
||||
qla_printk(KERN_INFO, ha,
|
||||
"Found an %s, irq %d, iobase 0x%p\n", ha->brd_info->isp_name,
|
||||
pdev->irq, ha->iobase);
|
||||
"Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq,
|
||||
ha->iobase);
|
||||
|
||||
spin_lock_init(&ha->hardware_lock);
|
||||
|
||||
|
@ -1368,9 +1367,11 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
|
|||
ha->isp_ops.reset_adapter = qla24xx_reset_adapter;
|
||||
ha->isp_ops.nvram_config = qla24xx_nvram_config;
|
||||
ha->isp_ops.update_fw_options = qla24xx_update_fw_options;
|
||||
#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
|
||||
ha->isp_ops.load_risc = qla24xx_load_risc_flash;
|
||||
if (ql2xfwloadbin)
|
||||
ha->isp_ops.load_risc = qla24xx_load_risc_hotplug;
|
||||
#else
|
||||
ha->isp_ops.load_risc = qla24xx_load_risc;
|
||||
#endif
|
||||
ha->isp_ops.pci_info_str = qla24xx_pci_info_str;
|
||||
ha->isp_ops.fw_version_str = qla24xx_fw_version_str;
|
||||
ha->isp_ops.intr_handler = qla24xx_intr_handler;
|
||||
|
@ -1531,11 +1532,12 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
|
|||
qla_printk(KERN_INFO, ha, "\n"
|
||||
" QLogic Fibre Channel HBA Driver: %s\n"
|
||||
" QLogic %s - %s\n"
|
||||
" %s: %s @ %s hdma%c, host#=%ld, fw=%s\n", qla2x00_version_str,
|
||||
ha->model_number, ha->model_desc ? ha->model_desc: "",
|
||||
ha->brd_info->isp_name, ha->isp_ops.pci_info_str(ha, pci_info),
|
||||
pci_name(pdev), ha->flags.enable_64bit_addressing ? '+': '-',
|
||||
ha->host_no, ha->isp_ops.fw_version_str(ha, fw_str));
|
||||
" ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
|
||||
qla2x00_version_str, ha->model_number,
|
||||
ha->model_desc ? ha->model_desc: "", pdev->device,
|
||||
ha->isp_ops.pci_info_str(ha, pci_info), pci_name(pdev),
|
||||
ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
|
||||
ha->isp_ops.fw_version_str(ha, fw_str));
|
||||
|
||||
/* Go with fc_rport registration. */
|
||||
list_for_each_entry(fcport, &ha->fcports, list)
|
||||
|
@ -2483,6 +2485,10 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
|
||||
|
||||
#define qla2x00_release_firmware() do { } while (0)
|
||||
|
||||
static struct qla_board_info qla_board_tbl[] = {
|
||||
{
|
||||
.drv_name = "qla2400",
|
||||
|
@ -2530,8 +2536,122 @@ qla2xxx_remove_one(struct pci_dev *pdev)
|
|||
qla2x00_remove_one(pdev);
|
||||
}
|
||||
|
||||
#else /* !defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE) */
|
||||
|
||||
/* Firmware interface routines. */
|
||||
|
||||
#define FW_BLOBS 6
|
||||
#define FW_ISP21XX 0
|
||||
#define FW_ISP22XX 1
|
||||
#define FW_ISP2300 2
|
||||
#define FW_ISP2322 3
|
||||
#define FW_ISP63XX 4
|
||||
#define FW_ISP24XX 5
|
||||
|
||||
static DECLARE_MUTEX(qla_fw_lock);
|
||||
|
||||
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
|
||||
{ .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
|
||||
{ .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
|
||||
{ .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
|
||||
{ .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
|
||||
{ .name = "ql6312_fw.bin", .segs = { 0x800, 0 }, },
|
||||
{ .name = "ql2400_fw.bin", },
|
||||
};
|
||||
|
||||
struct fw_blob *
|
||||
qla2x00_request_firmware(scsi_qla_host_t *ha)
|
||||
{
|
||||
struct fw_blob *blob;
|
||||
|
||||
blob = NULL;
|
||||
if (IS_QLA2100(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP21XX];
|
||||
} else if (IS_QLA2200(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP22XX];
|
||||
} else if (IS_QLA2300(ha) || IS_QLA2312(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP2300];
|
||||
} else if (IS_QLA2322(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP2322];
|
||||
} else if (IS_QLA6312(ha) || IS_QLA6322(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP63XX];
|
||||
} else if (IS_QLA24XX(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP24XX];
|
||||
}
|
||||
|
||||
down(&qla_fw_lock);
|
||||
if (blob->fw)
|
||||
goto out;
|
||||
|
||||
if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) {
|
||||
DEBUG2(printk("scsi(%ld): Failed to load firmware image "
|
||||
"(%s).\n", ha->host_no, blob->name));
|
||||
blob->fw = NULL;
|
||||
blob = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
up(&qla_fw_lock);
|
||||
return blob;
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_release_firmware(void)
|
||||
{
|
||||
int idx;
|
||||
|
||||
down(&qla_fw_lock);
|
||||
for (idx = 0; idx < FW_BLOBS; idx++)
|
||||
if (qla_fw_blobs[idx].fw)
|
||||
release_firmware(qla_fw_blobs[idx].fw);
|
||||
up(&qla_fw_lock);
|
||||
}
|
||||
|
||||
static struct qla_board_info qla_board_tbl = {
|
||||
.drv_name = "qla2xxx",
|
||||
};
|
||||
|
||||
static struct pci_device_id qla2xxx_pci_tbl[] = {
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2300,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2312,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2322,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6312,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432,
|
||||
PCI_ANY_ID, PCI_ANY_ID, },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
|
||||
|
||||
static int __devinit
|
||||
qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
return qla2x00_probe_one(pdev, &qla_board_tbl);
|
||||
}
|
||||
|
||||
static void __devexit
|
||||
qla2xxx_remove_one(struct pci_dev *pdev)
|
||||
{
|
||||
qla2x00_remove_one(pdev);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct pci_driver qla2xxx_pci_driver = {
|
||||
.name = "qla2xxx",
|
||||
.owner = THIS_MODULE,
|
||||
.id_table = qla2xxx_pci_tbl,
|
||||
.probe = qla2xxx_probe_one,
|
||||
.remove = __devexit_p(qla2xxx_remove_one),
|
||||
|
@ -2556,6 +2676,9 @@ qla2x00_module_init(void)
|
|||
|
||||
/* Derive version string. */
|
||||
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
|
||||
#if defined(CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE)
|
||||
strcat(qla2x00_version_str, "-fw");
|
||||
#endif
|
||||
#if DEBUG_QLA2100
|
||||
strcat(qla2x00_version_str, "-debug");
|
||||
#endif
|
||||
|
@ -2580,6 +2703,7 @@ static void __exit
|
|||
qla2x00_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&qla2xxx_pci_driver);
|
||||
qla2x00_release_firmware();
|
||||
kmem_cache_destroy(srb_cachep);
|
||||
fc_release_transport(qla2xxx_transport_template);
|
||||
}
|
||||
|
|
Reference in a new issue