提交 5433383e 编写于 作者: A Andrew Vasquez 提交者: James Bottomley

[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: NAndrew Vasquez <andrew.vasquez@qlogic.com>

Rejections fixed up and
Signed-off-by: NJames Bottomley <James.Bottomley@SteelEye.com>
上级 26a68019
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.
config SCSI_QLA21XX
tristate "QLogic ISP2100 host adapter family support"
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
select SCSI_FC_ATTRS
select FW_LOADER
config SCSI_QLA21XX
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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册