/*
* Ioctl related information.
*/
-static int num_hosts;
-
+int num_hosts;
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
"Login timeout value in seconds.");
-int qlport_down_retry = 30;
+int qlport_down_retry;
module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(qlport_down_retry,
"Maximum number of command retries to a port that returns "
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
-static struct scsi_host_template qla2x00_driver_template = {
+struct scsi_host_template qla2x00_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla2x00_queuecommand,
.shost_attrs = qla2x00_host_attrs,
};
-static struct scsi_host_template qla24xx_driver_template = {
+struct scsi_host_template qla24xx_driver_template = {
.module = THIS_MODULE,
.name = QLA2XXX_DRIVER_NAME,
.queuecommand = qla24xx_queuecommand,
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
/* TODO Convert to inlines
*
* Timer routines
*/
-#define WATCH_INTERVAL 1 /* number of seconds */
-static void qla2x00_timer(scsi_qla_host_t *);
+void qla2x00_timer(scsi_qla_host_t *);
-static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
void *, unsigned long);
static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
-static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
-static inline void
+__inline__ void
qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
{
init_timer(&ha->timer);
mod_timer(&ha->timer, jiffies + interval * HZ);
}
-static __inline__ void
+__inline__ void
qla2x00_stop_timer(scsi_qla_host_t *ha)
{
del_timer_sync(&ha->timer);
static void qla2x00_rst_aen(scsi_qla_host_t *);
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
-static void qla2x00_mem_free(scsi_qla_host_t *ha);
+uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+void qla2x00_mem_free(scsi_qla_host_t *ha);
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
srb_t *sp;
int rval;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
rval = fc_remote_port_chkready(rport);
if (rval) {
if (atomic_read(&fcport->state) != FCS_ONLINE) {
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
- atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ atomic_read(&pha->loop_state) == LOOP_DEAD) {
cmd->result = DID_NO_CONNECT << 16;
goto qc24_fail_command;
}
spin_unlock_irq(ha->host->host_lock);
- sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
+ sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
if (!sp)
goto qc24_host_busy_lock;
return 0;
qc24_host_busy_free_sp:
- qla2x00_sp_free_dma(ha, sp);
- mempool_free(sp, ha->srb_mempool);
+ qla2x00_sp_free_dma(pha, sp);
+ mempool_free(sp, pha->srb_mempool);
qc24_host_busy_lock:
spin_lock_irq(ha->host->host_lock);
{
int return_status;
unsigned long wait_online;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
- test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
- test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
- ha->dpc_active) && time_before(jiffies, wait_online)) {
+ while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
+ test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
+ test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
+ pha->dpc_active) && time_before(jiffies, wait_online)) {
msleep(1000);
}
- if (ha->flags.online)
+ if (pha->flags.online)
return_status = QLA_SUCCESS;
else
return_status = QLA_FUNCTION_FAILED;
{
int return_status = QLA_SUCCESS;
unsigned long loop_timeout ;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/* wait for 5 min at the max for loop to be ready */
loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
- while ((!atomic_read(&ha->loop_down_timer) &&
- atomic_read(&ha->loop_state) == LOOP_DOWN) ||
- atomic_read(&ha->loop_state) != LOOP_READY) {
- if (atomic_read(&ha->loop_state) == LOOP_DEAD) {
+ while ((!atomic_read(&pha->loop_down_timer) &&
+ atomic_read(&pha->loop_state) == LOOP_DOWN) ||
+ atomic_read(&pha->loop_state) != LOOP_READY) {
+ if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
return_status = QLA_FUNCTION_FAILED;
break;
}
unsigned long serial;
unsigned long flags;
int wait = 0;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
serial = cmd->serial_number;
/* Check active list for command command. */
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
- sp = ha->outstanding_cmds[i];
+ sp = pha->outstanding_cmds[i];
if (sp == NULL)
continue;
__func__, ha->host_no, sp, serial));
DEBUG3(qla2x00_print_scsi_cmd(cmd));
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
if (ha->isp_ops.abort_command(ha, sp)) {
DEBUG2(printk("%s(%ld): abort_command "
"mbx failed.\n", __func__, ha->host_no));
"mbx success.\n", __func__, ha->host_no));
wait = 1;
}
- spin_lock_irqsave(&ha->hardware_lock, flags);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
break;
}
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
/* Wait for the command to be returned. */
if (wait) {
srb_t *sp;
struct scsi_cmnd *cmd;
unsigned long flags;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
status = 0;
* array
*/
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp = ha->outstanding_cmds[cnt];
+ spin_lock_irqsave(&pha->hardware_lock, flags);
+ sp = pha->outstanding_cmds[cnt];
if (sp) {
cmd = sp->cmd;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- if (cmd->device->id == t) {
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+ if (cmd->device->id == t &&
+ ha->vp_idx == sp->ha->vp_idx) {
if (!qla2x00_eh_wait_on_command(ha, cmd)) {
status = 1;
break;
}
}
} else {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
}
}
return (status);
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
+ scsi_qla_host_t *pha = to_qla_parent(ha);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
goto eh_bus_reset_done;
/* Flush outstanding commands. */
- if (!qla2x00_eh_wait_for_pending_commands(ha))
+ if (!qla2x00_eh_wait_for_pending_commands(pha))
ret = FAILED;
eh_bus_reset_done:
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret;
+ int ret = FAILED;
unsigned int id, lun;
unsigned long serial;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
qla2x00_block_error_handler(cmd);
- ret = FAILED;
-
id = cmd->device->id;
lun = cmd->device->lun;
serial = cmd->serial_number;
* while dpc is stuck for the mailbox to complete.
*/
qla2x00_wait_for_loop_ready(ha);
- set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- if (qla2x00_abort_isp(ha)) {
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
+ if (qla2x00_abort_isp(pha)) {
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* failed. schedule dpc to try */
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+ set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
goto eh_host_reset_lock;
}
- clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+ clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
/* Waiting for our command in done_queue to be returned to OS.*/
- if (qla2x00_eh_wait_for_pending_commands(ha))
+ if (qla2x00_eh_wait_for_pending_commands(pha))
ret = SUCCESS;
+ if (ha->parent)
+ qla2x00_vp_abort_isp(ha);
+
eh_host_reset_lock:
qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
(ret == FAILED) ? "failed" : "succeded");
case PCI_DEVICE_ID_QLOGIC_ISP2422:
ha->device_type |= DT_ISP2422;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP2432:
ha->device_type |= DT_ISP2432;
ha->device_type |= DT_ZIO_SUPPORTED;
+ ha->device_type |= DT_FWI2;
+ ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5422:
ha->device_type |= DT_ISP5422;
+ ha->device_type |= DT_FWI2;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
case PCI_DEVICE_ID_QLOGIC_ISP5432:
ha->device_type |= DT_ISP5432;
+ ha->device_type |= DT_FWI2;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
}
ha->host = host;
ha->host_no = host->host_no;
sprintf(ha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, ha->host_no);
+ ha->parent = NULL;
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
- ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
+ ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
- ha->init_cb_size = sizeof(struct init_cb_24xx);
- ha->mgmt_svr_loop_id = 10;
+ ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+ ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
ha->isp_ops.pci_config = qla24xx_pci_config;
ha->isp_ops.reset_chip = qla24xx_reset_chip;
ha->isp_ops.chip_diag = qla24xx_chip_diag;
ha->instance = num_hosts;
init_MUTEX(&ha->mbx_cmd_sem);
+ init_MUTEX(&ha->vport_sem);
init_MUTEX_LOCKED(&ha->mbx_intr_sem);
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
+ INIT_LIST_HEAD(&ha->vp_list);
+
+ set_bit(0, (unsigned long *) ha->vp_idx_map);
qla2x00_config_dma_addressing(ha);
if (qla2x00_mem_alloc(ha)) {
goto probe_failed;
}
- if (qla2x00_initialize_adapter(ha) &&
- !(ha->device_flags & DFLG_NO_CABLE)) {
-
+ if (qla2x00_initialize_adapter(ha)) {
qla_printk(KERN_WARNING, ha,
"Failed to initialize adapter\n");
spin_lock_irqsave(&ha->hardware_lock, flags);
reg = ha->iobase;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT);
WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT);
} else {
void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
int do_login, int defer)
{
- if (atomic_read(&fcport->state) == FCS_ONLINE)
+ if (atomic_read(&fcport->state) == FCS_ONLINE &&
+ ha->vp_idx == fcport->vp_idx)
qla2x00_schedule_rport_del(ha, fcport, defer);
/*
qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha, int defer)
{
fc_port_t *fcport;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
- list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
+ list_for_each_entry(fcport, &pha->fcports, list) {
+ if (ha->vp_idx != 0 && ha->vp_idx != fcport->vp_idx)
continue;
-
/*
* No point in marking the device as lost, if the device is
* already DEAD.
*/
if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
continue;
- if (atomic_read(&fcport->state) == FCS_ONLINE)
- qla2x00_schedule_rport_del(ha, fcport, defer);
+ if (atomic_read(&fcport->state) == FCS_ONLINE) {
+ if (defer)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ else if (ha->vp_idx == fcport->vp_idx)
+ qla2x00_schedule_rport_del(ha, fcport, defer);
+ }
atomic_set(&fcport->state, FCS_DEVICE_LOST);
}
* 0 = success.
* 1 = failure.
*/
-static uint8_t
+uint8_t
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
continue;
}
- snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
- ha->host_no);
- ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
- DMA_POOL_SIZE, 8, 0);
- if (ha->s_dma_pool == NULL) {
+ /* get consistent memory allocated for init control block */
+ ha->init_cb = dma_alloc_coherent(&ha->pdev->dev,
+ ha->init_cb_size, &ha->init_cb_dma, GFP_KERNEL);
+ if (ha->init_cb == NULL) {
qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - s_dma_pool\n");
+ "Memory Allocation failed - init_cb\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
+ memset(ha->init_cb, 0, ha->init_cb_size);
- /* get consistent memory allocated for init control block */
- ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
- &ha->init_cb_dma);
- if (ha->init_cb == NULL) {
+ snprintf(name, sizeof(name), "%s_%ld", QLA2XXX_DRIVER_NAME,
+ ha->host_no);
+ ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+ DMA_POOL_SIZE, 8, 0);
+ if (ha->s_dma_pool == NULL) {
qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - init_cb\n");
+ "Memory Allocation failed - s_dma_pool\n");
qla2x00_mem_free(ha);
msleep(100);
continue;
}
- memset(ha->init_cb, 0, ha->init_cb_size);
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ if (IS_FWI2_CAPABLE(ha)) {
/*
* Get consistent memory allocated for SFP
* block.
* Input:
* ha = adapter block pointer.
*/
-static void
+void
qla2x00_mem_free(scsi_qla_host_t *ha)
{
struct list_head *fcpl, *fcptemp;
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
- if (ha->init_cb)
- dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
-
if (ha->s_dma_pool)
dma_pool_destroy(ha->s_dma_pool);
+ if (ha->init_cb)
+ dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
+ ha->init_cb, ha->init_cb_dma);
+
if (ha->gid_list)
dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
ha->gid_list_dma);
static int
qla2x00_do_dpc(void *data)
{
+ int rval;
scsi_qla_host_t *ha;
fc_port_t *fcport;
uint8_t status;
if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
&ha->dpc_flags))) {
- qla2x00_loop_resync(ha);
+ rval = qla2x00_loop_resync(ha);
clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
}
if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
ha->isp_ops.beacon_blink(ha);
+ qla2x00_do_dpc_all_vps(ha);
+
ha->dpc_active = 0;
} /* End of while(1) */
struct scsi_cmnd *cmd = sp->cmd;
if (sp->flags & SRB_DMA_VALID) {
- if (cmd->use_sg) {
- dma_unmap_sg(&ha->pdev->dev, cmd->request_buffer,
- cmd->use_sg, cmd->sc_data_direction);
- } else if (cmd->request_bufflen) {
- dma_unmap_single(&ha->pdev->dev, sp->dma_handle,
- cmd->request_bufflen, cmd->sc_data_direction);
- }
+ scsi_dma_unmap(cmd);
sp->flags &= ~SRB_DMA_VALID;
}
CMD_SP(cmd) = NULL;
*
* Context: Interrupt
***************************************************************************/
-static void
+void
qla2x00_timer(scsi_qla_host_t *ha)
{
unsigned long cpu_flags = 0;
int index;
srb_t *sp;
int t;
+ scsi_qla_host_t *pha = to_qla_parent(ha);
/*
* Ports - Port down timer.
atomic_set(&ha->loop_state, LOOP_DEAD);
/* Schedule an ISP abort to return any tape commands. */
- spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
- for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
- index++) {
- fc_port_t *sfcp;
+ /* NPIV - scan physical port only */
+ if (!ha->parent) {
+ spin_lock_irqsave(&ha->hardware_lock,
+ cpu_flags);
+ for (index = 1;
+ index < MAX_OUTSTANDING_COMMANDS;
+ index++) {
+ fc_port_t *sfcp;
+
+ sp = ha->outstanding_cmds[index];
+ if (!sp)
+ continue;
+ sfcp = sp->fcport;
+ if (!(sfcp->flags & FCF_TAPE_PRESENT))
+ continue;
- sp = ha->outstanding_cmds[index];
- if (!sp)
- continue;
- sfcp = sp->fcport;
- if (!(sfcp->flags & FCF_TAPE_PRESENT))
- continue;
-
- set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
- break;
+ set_bit(ISP_ABORT_NEEDED,
+ &ha->dpc_flags);
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ cpu_flags);
}
- spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
-
set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
start_dpc++;
}
test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) ||
test_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags) ||
+ test_bit(VP_DPC_NEEDED, &ha->dpc_flags) ||
test_bit(RELOGIN_NEEDED, &ha->dpc_flags)))
- qla2xxx_wake_dpc(ha);
+ qla2xxx_wake_dpc(pha);
qla2x00_restart_timer(ha, WATCH_INTERVAL);
}
return 0;
if (msleep_interruptible(step))
break;
- } while (--iterations >= 0);
+ } while (--iterations > 0);
return -ETIMEDOUT;
}
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
- if (!qla2xxx_transport_template)
+ if (!qla2xxx_transport_template) {
+ kmem_cache_destroy(srb_cachep);
return -ENODEV;
+ }
+ qla2xxx_transport_vport_template =
+ fc_attach_transport(&qla2xxx_transport_vport_functions);
+ if (!qla2xxx_transport_vport_template) {
+ kmem_cache_destroy(srb_cachep);
+ fc_release_transport(qla2xxx_transport_template);
+ return -ENODEV;
+ }
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
return ret;
}
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
+ fc_release_transport(qla2xxx_transport_vport_template);
}
module_init(qla2x00_module_init);