/*
* QLogic Fibre Channel HBA Driver
- * Copyright (c) 2003-2005 QLogic Corporation
+ * Copyright (c) 2003-2008 QLogic Corporation
*
* See LICENSE.qla2xxx for copyright and licensing details.
*/
*/
static struct kmem_cache *srb_cachep;
-/*
- * Ioctl related information.
- */
int num_hosts;
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
void (*fn)(struct scsi_cmnd *));
static int qla2xxx_eh_abort(struct scsi_cmnd *);
static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
+static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);
.eh_abort_handler = qla2xxx_eh_abort,
.eh_device_reset_handler = qla2xxx_eh_device_reset,
+ .eh_target_reset_handler = qla2xxx_eh_target_reset,
.eh_bus_reset_handler = qla2xxx_eh_bus_reset,
.eh_host_reset_handler = qla2xxx_eh_host_reset,
.eh_abort_handler = qla2xxx_eh_abort,
.eh_device_reset_handler = qla2xxx_eh_device_reset,
+ .eh_target_reset_handler = qla2xxx_eh_target_reset,
.eh_bus_reset_handler = qla2xxx_eh_bus_reset,
.eh_host_reset_handler = qla2xxx_eh_host_reset,
static void qla2x00_rst_aen(scsi_qla_host_t *);
-static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+static int qla2x00_mem_alloc(scsi_qla_host_t *);
static 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 *);
/* -------------------------------------------------------------------------- */
strcpy(str, "PCIe (");
if (lspeed == 1)
- strcat(str, "2.5Gb/s ");
+ strcat(str, "2.5GT/s ");
else if (lspeed == 2)
- strcat(str, "5.0Gb/s ");
+ strcat(str, "5.0GT/s ");
else
strcat(str, "<unknown> ");
snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
strcat(str, "[T10 CRC] ");
if (ha->fw_attributes & BIT_5)
strcat(str, "[VI] ");
+ if (ha->fw_attributes & BIT_10)
+ strcat(str, "[84XX] ");
if (ha->fw_attributes & BIT_13)
strcat(str, "[Experimental]");
return str;
else
return_status = QLA_FUNCTION_FAILED;
- DEBUG2(printk("%s return_status=%d\n",__func__,return_status));
-
return (return_status);
}
DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",
__func__, ha->host_no, sp, serial));
- DEBUG3(qla2x00_print_scsi_cmd(cmd));
spin_unlock_irqrestore(&pha->hardware_lock, flags);
if (ha->isp_ops->abort_command(ha, sp)) {
return ret;
}
-/**************************************************************************
-* qla2x00_eh_wait_for_pending_target_commands
-*
-* Description:
-* Waits for all the commands to come back from the specified target.
-*
-* Input:
-* ha - pointer to scsi_qla_host structure.
-* t - target
-* Returns:
-* Either SUCCESS or FAILED.
-*
-* Note:
-**************************************************************************/
+enum nexus_wait_type {
+ WAIT_HOST = 0,
+ WAIT_TARGET,
+ WAIT_LUN,
+};
+
static int
-qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
+qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha, unsigned int t,
+ unsigned int l, enum nexus_wait_type type)
{
- int cnt;
- int status;
- srb_t *sp;
- struct scsi_cmnd *cmd;
+ int cnt, match, status;
+ srb_t *sp;
unsigned long flags;
scsi_qla_host_t *pha = to_qla_parent(ha);
- status = 0;
-
- /*
- * Waiting for all commands for the designated target in the active
- * array
- */
- for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- spin_lock_irqsave(&pha->hardware_lock, flags);
+ status = QLA_SUCCESS;
+ spin_lock_irqsave(&pha->hardware_lock, flags);
+ for (cnt = 1; status == QLA_SUCCESS && cnt < MAX_OUTSTANDING_COMMANDS;
+ cnt++) {
sp = pha->outstanding_cmds[cnt];
- if (sp) {
- cmd = sp->cmd;
- 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(&pha->hardware_lock, flags);
+ if (!sp)
+ continue;
+ if (ha->vp_idx != sp->ha->vp_idx)
+ continue;
+ match = 0;
+ switch (type) {
+ case WAIT_HOST:
+ match = 1;
+ break;
+ case WAIT_TARGET:
+ match = sp->cmd->device->id == t;
+ break;
+ case WAIT_LUN:
+ match = (sp->cmd->device->id == t &&
+ sp->cmd->device->lun == l);
+ break;
}
+ if (!match)
+ continue;
+
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+ status = qla2x00_eh_wait_on_command(ha, sp->cmd);
+ spin_lock_irqsave(&pha->hardware_lock, flags);
}
- return (status);
+ spin_unlock_irqrestore(&pha->hardware_lock, flags);
+
+ return status;
}
+static char *reset_errors[] = {
+ "HBA not online",
+ "HBA not ready",
+ "Task management failed",
+ "Waiting for command completions",
+};
-/**************************************************************************
-* qla2xxx_eh_device_reset
-*
-* Description:
-* The device reset function will reset the target and abort any
-* executing commands.
-*
-* NOTE: The use of SP is undefined within this context. Do *NOT*
-* attempt to use this value, even if you determine it is
-* non-null.
-*
-* Input:
-* cmd = Linux SCSI command packet of the command that cause the
-* bus device reset.
-*
-* Returns:
-* SUCCESS/FAILURE (defined as macro in scsi.h).
-*
-**************************************************************************/
static int
-qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
+__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type,
+ struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int))
{
scsi_qla_host_t *ha = shost_priv(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- int ret = FAILED;
- unsigned int id, lun;
- unsigned long serial;
+ int err;
qla2x00_block_error_handler(cmd);
- id = cmd->device->id;
- lun = cmd->device->lun;
- serial = cmd->serial_number;
-
if (!fcport)
- return ret;
+ return FAILED;
- qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun);
+ qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET ISSUED.\n",
+ ha->host_no, cmd->device->id, cmd->device->lun, name);
+ err = 0;
if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
- goto eh_dev_reset_done;
-
- if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
- if (qla2x00_device_reset(ha, fcport) == 0)
- ret = SUCCESS;
-
-#if defined(LOGOUT_AFTER_DEVICE_RESET)
- if (ret == SUCCESS) {
- if (fcport->flags & FC_FABRIC_DEVICE) {
- ha->isp_ops->fabric_logout(ha, fcport->loop_id);
- qla2x00_mark_device_lost(ha, fcport, 0, 0);
- }
- }
-#endif
- } else {
- DEBUG2(printk(KERN_INFO
- "%s failed: loop not ready\n",__func__));
- }
-
- if (ret == FAILED) {
- DEBUG3(printk("%s(%ld): device reset failed\n",
- __func__, ha->host_no));
- qla_printk(KERN_INFO, ha, "%s: device reset failed\n",
- __func__);
+ goto eh_reset_failed;
+ err = 1;
+ if (qla2x00_wait_for_loop_ready(ha) != QLA_SUCCESS)
+ goto eh_reset_failed;
+ err = 2;
+ if (do_reset(fcport, cmd->device->lun) != QLA_SUCCESS)
+ goto eh_reset_failed;
+ err = 3;
+ if (qla2x00_eh_wait_for_pending_commands(ha, cmd->device->id,
+ cmd->device->lun, type) != QLA_SUCCESS)
+ goto eh_reset_failed;
+
+ qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET SUCCEEDED.\n",
+ ha->host_no, cmd->device->id, cmd->device->lun, name);
+
+ return SUCCESS;
+
+ eh_reset_failed:
+ qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): %s RESET FAILED: %s.\n",
+ ha->host_no, cmd->device->id, cmd->device->lun, name,
+ reset_errors[err]);
+ return FAILED;
+}
- goto eh_dev_reset_done;
- }
+static int
+qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
+{
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
- /* Flush outstanding commands. */
- if (qla2x00_eh_wait_for_pending_target_commands(ha, id))
- ret = FAILED;
- if (ret == FAILED) {
- DEBUG3(printk("%s(%ld): failed while waiting for commands\n",
- __func__, ha->host_no));
- qla_printk(KERN_INFO, ha,
- "%s: failed while waiting for commands\n", __func__);
- } else
- qla_printk(KERN_INFO, ha,
- "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no,
- id, lun);
- eh_dev_reset_done:
- return ret;
+ return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd,
+ ha->isp_ops->lun_reset);
}
-/**************************************************************************
-* qla2x00_eh_wait_for_pending_commands
-*
-* Description:
-* Waits for all the commands to come back from the specified host.
-*
-* Input:
-* ha - pointer to scsi_qla_host structure.
-*
-* Returns:
-* 1 : SUCCESS
-* 0 : FAILED
-*
-* Note:
-**************************************************************************/
static int
-qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
+qla2xxx_eh_target_reset(struct scsi_cmnd *cmd)
{
- int cnt;
- int status;
- srb_t *sp;
- struct scsi_cmnd *cmd;
- unsigned long flags;
-
- status = 1;
+ scsi_qla_host_t *ha = shost_priv(cmd->device->host);
- /*
- * Waiting for all commands for the designated target in the active
- * array
- */
- for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
- spin_lock_irqsave(&ha->hardware_lock, flags);
- sp = ha->outstanding_cmds[cnt];
- if (sp) {
- cmd = sp->cmd;
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- status = qla2x00_eh_wait_on_command(ha, cmd);
- if (status == 0)
- break;
- }
- else {
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
- }
- }
- return (status);
+ return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd,
+ ha->isp_ops->target_reset);
}
-
/**************************************************************************
* qla2xxx_eh_bus_reset
*
goto eh_bus_reset_done;
/* Flush outstanding commands. */
- if (!qla2x00_eh_wait_for_pending_commands(pha))
+ if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) !=
+ QLA_SUCCESS)
ret = FAILED;
eh_bus_reset_done:
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(pha))
+ if (qla2x00_eh_wait_for_pending_commands(pha, 0, 0, WAIT_HOST) ==
+ QLA_SUCCESS)
ret = SUCCESS;
if (ha->parent)
if (fcport->port_type != FCT_TARGET)
continue;
- ret = qla2x00_device_reset(ha, fcport);
+ ret = ha->isp_ops->target_reset(fcport, 0);
if (ret != QLA_SUCCESS) {
DEBUG2_3(printk("%s(%ld): bus_reset failed: "
"target_reset=%d d_id=%x.\n", __func__,
return QLA_SUCCESS;
}
-/*
- * qla2x00_device_reset
- * Issue bus device reset message to the target.
- *
- * Input:
- * ha = adapter block pointer.
- * t = SCSI ID.
- * TARGET_QUEUE_LOCK must be released.
- * ADAPTER_STATE_LOCK must be released.
- *
- * Context:
- * Kernel context.
- */
-static int
-qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
+void
+qla2x00_abort_all_cmds(scsi_qla_host_t *ha, int res)
{
- /* Abort Target command will clear Reservation */
- return ha->isp_ops->abort_target(reset_fcport);
+ int cnt;
+ unsigned long flags;
+ srb_t *sp;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+ sp = ha->outstanding_cmds[cnt];
+ if (sp) {
+ ha->outstanding_cmds[cnt] = NULL;
+ sp->flags = 0;
+ sp->cmd->result = res;
+ sp->cmd->host_scribble = (unsigned char *)NULL;
+ qla2x00_sp_compl(ha, sp);
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
static int
.enable_intrs = qla2x00_enable_intrs,
.disable_intrs = qla2x00_disable_intrs,
.abort_command = qla2x00_abort_command,
- .abort_target = qla2x00_abort_target,
+ .target_reset = qla2x00_abort_target,
+ .lun_reset = qla2x00_lun_reset,
.fabric_login = qla2x00_login_fabric,
.fabric_logout = qla2x00_fabric_logout,
.calc_req_entries = qla2x00_calc_iocbs_32,
.enable_intrs = qla2x00_enable_intrs,
.disable_intrs = qla2x00_disable_intrs,
.abort_command = qla2x00_abort_command,
- .abort_target = qla2x00_abort_target,
+ .target_reset = qla2x00_abort_target,
+ .lun_reset = qla2x00_lun_reset,
.fabric_login = qla2x00_login_fabric,
.fabric_logout = qla2x00_fabric_logout,
.calc_req_entries = qla2x00_calc_iocbs_32,
.enable_intrs = qla24xx_enable_intrs,
.disable_intrs = qla24xx_disable_intrs,
.abort_command = qla24xx_abort_command,
- .abort_target = qla24xx_abort_target,
+ .target_reset = qla24xx_abort_target,
+ .lun_reset = qla24xx_lun_reset,
.fabric_login = qla24xx_login_fabric,
.fabric_logout = qla24xx_fabric_logout,
.calc_req_entries = NULL,
.enable_intrs = qla24xx_enable_intrs,
.disable_intrs = qla24xx_disable_intrs,
.abort_command = qla24xx_abort_command,
- .abort_target = qla24xx_abort_target,
+ .target_reset = qla24xx_abort_target,
+ .lun_reset = qla24xx_lun_reset,
.fabric_login = qla24xx_login_fabric,
.fabric_logout = qla24xx_fabric_logout,
.calc_req_entries = NULL,
ha->device_type |= DT_IIDMA;
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
break;
+ case PCI_DEVICE_ID_QLOGIC_ISP8432:
+ ha->device_type |= DT_ISP8432;
+ 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;
qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret = -ENODEV;
- device_reg_t __iomem *reg;
struct Scsi_Host *host;
scsi_qla_host_t *ha;
- unsigned long flags = 0;
char pci_info[30];
char fw_str[30];
struct scsi_host_template *sht;
sht = &qla2x00_driver_template;
if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
+ pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) {
ha->parent = NULL;
ha->bars = bars;
ha->mem_only = mem_only;
+ spin_lock_init(&ha->hardware_lock);
/* Set ISP-type information. */
qla2x00_set_isp_flags(ha);
"Found an ISP%04X, irq %d, iobase 0x%p\n", pdev->device, pdev->irq,
ha->iobase);
- spin_lock_init(&ha->hardware_lock);
-
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER + ha->vp_idx;
if (IS_QLA2322(ha) || IS_QLA6322(ha))
ha->optrom_size = OPTROM_SIZE_2322;
ha->isp_ops = &qla2300_isp_ops;
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ } else if (IS_QLA24XX_TYPE(ha)) {
host->max_id = MAX_TARGETS_2200;
ha->mbx_count = MAILBOX_REGISTER_COUNT;
ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
ha->gid_list_info_size = 8;
ha->optrom_size = OPTROM_SIZE_25XX;
ha->isp_ops = &qla25xx_isp_ops;
+ ha->hw_event_start = PCI_FUNC(pdev->devfn) ?
+ FA_HW_EVENT1_ADDR: FA_HW_EVENT0_ADDR;
}
host->can_queue = ha->request_q_length + 128;
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
INIT_LIST_HEAD(&ha->vp_list);
+ INIT_LIST_HEAD(&ha->work_list);
set_bit(0, (unsigned long *) ha->vp_idx_map);
DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
ha->host_no, ha));
- ha->isp_ops->disable_intrs(ha);
-
- spin_lock_irqsave(&ha->hardware_lock, flags);
- reg = ha->iobase;
- if (IS_FWI2_CAPABLE(ha)) {
- WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT);
- WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT);
- } else {
- WRT_REG_WORD(®->isp.semaphore, 0);
- WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT);
- WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT);
-
- /* Enable proper parity */
- if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) {
- if (IS_QLA2300(ha))
- /* SRAM parity */
- WRT_REG_WORD(®->isp.hccr,
- (HCCR_ENABLE_PARITY + 0x1));
- else
- /* SRAM, Instruction RAM and GP RAM parity */
- WRT_REG_WORD(®->isp.hccr,
- (HCCR_ENABLE_PARITY + 0x7));
- }
- }
- spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
- ha->isp_ops->enable_intrs(ha);
-
pci_set_drvdata(pdev, ha);
ha->flags.init_done = 1;
qla2x00_dfs_remove(ha);
+ qla84xx_put_chip(ha);
+
qla2x00_free_sysfs_attr(ha);
fc_remove_host(ha->host);
static void
qla2x00_free_device(scsi_qla_host_t *ha)
{
+ qla2x00_abort_all_cmds(ha, DID_NO_CONNECT << 16);
+
/* Disable timer */
if (ha->timer_active)
qla2x00_stop_timer(ha);
+ ha->flags.online = 0;
+
/* Kill the kernel thread for this host */
if (ha->dpc_thread) {
struct task_struct *t = ha->dpc_thread;
if (ha->eft)
qla2x00_disable_eft_trace(ha);
- ha->flags.online = 0;
-
/* Stop currently executing firmware. */
qla2x00_try_to_stop_firmware(ha);
*
* Returns:
* 0 = success.
-* 1 = failure.
+* !0 = failure.
*/
-static uint8_t
+static int
qla2x00_mem_alloc(scsi_qla_host_t *ha)
{
char name[16];
- uint8_t status = 1;
- int retry= 10;
-
- do {
- /*
- * This will loop only once if everything goes well, else some
- * number of retries will be performed to get around a kernel
- * bug where available mem is not allocated until after a
- * little delay and a retry.
- */
- ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
- (ha->request_q_length + 1) * sizeof(request_t),
- &ha->request_dma, GFP_KERNEL);
- if (ha->request_ring == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - request_ring\n");
- qla2x00_mem_free(ha);
- msleep(100);
+ ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
+ (ha->request_q_length + 1) * sizeof(request_t), &ha->request_dma,
+ GFP_KERNEL);
+ if (!ha->request_ring)
+ goto fail;
+
+ ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
+ (ha->response_q_length + 1) * sizeof(response_t),
+ &ha->response_dma, GFP_KERNEL);
+ if (!ha->response_ring)
+ goto fail_free_request_ring;
+
+ ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
+ &ha->gid_list_dma, GFP_KERNEL);
+ if (!ha->gid_list)
+ goto fail_free_response_ring;
+
+ ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size,
+ &ha->init_cb_dma, GFP_KERNEL);
+ if (!ha->init_cb)
+ goto fail_free_gid_list;
+
+ 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)
+ goto fail_free_init_cb;
- continue;
- }
-
- ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
- (ha->response_q_length + 1) * sizeof(response_t),
- &ha->response_dma, GFP_KERNEL);
- if (ha->response_ring == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - response_ring\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
- &ha->gid_list_dma, GFP_KERNEL);
- if (ha->gid_list == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - gid_list\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- /* 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 - init_cb\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->init_cb, 0, ha->init_cb_size);
-
- 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 - s_dma_pool\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- if (qla2x00_allocate_sp_pool(ha)) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - "
- "qla2x00_allocate_sp_pool()\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- /* Allocate memory for SNS commands */
- if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
- /* Get consistent memory allocated for SNS commands */
- ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev,
- sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma,
- GFP_KERNEL);
- if (ha->sns_cmd == NULL) {
- /* error */
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - sns_cmd\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt));
- } else {
- /* Get consistent memory allocated for MS IOCB */
- ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
- &ha->ms_iocb_dma);
- if (ha->ms_iocb == NULL) {
- /* error */
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - ms_iocb\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t));
-
- /*
- * Get consistent memory allocated for CT SNS
- * commands
- */
- ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev,
- sizeof(struct ct_sns_pkt), &ha->ct_sns_dma,
- GFP_KERNEL);
- if (ha->ct_sns == NULL) {
- /* error */
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - ct_sns\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
-
- if (IS_FWI2_CAPABLE(ha)) {
- /*
- * Get consistent memory allocated for SFP
- * block.
- */
- ha->sfp_data = dma_pool_alloc(ha->s_dma_pool,
- GFP_KERNEL, &ha->sfp_data_dma);
- if (ha->sfp_data == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - "
- "sfp_data\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
- memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
- }
- }
-
- /* Get memory for cached NVRAM */
- ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
- if (ha->nvram == NULL) {
- /* error */
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - nvram cache\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
- /* Done all allocations without any error. */
- status = 0;
-
- } while (retry-- && status != 0);
+ ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
+ if (!ha->srb_mempool)
+ goto fail_free_s_dma_pool;
+
+ /* Get memory for cached NVRAM */
+ ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
+ if (!ha->nvram)
+ goto fail_free_srb_mempool;
+
+ /* Allocate memory for SNS commands */
+ if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+ /* Get consistent memory allocated for SNS commands */
+ ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL);
+ if (!ha->sns_cmd)
+ goto fail_free_nvram;
+ } else {
+ /* Get consistent memory allocated for MS IOCB */
+ ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+ &ha->ms_iocb_dma);
+ if (!ha->ms_iocb)
+ goto fail_free_nvram;
- if (status) {
- printk(KERN_WARNING
- "%s(): **** FAILED ****\n", __func__);
+ /* Get consistent memory allocated for CT SNS commands */
+ ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
+ if (!ha->ct_sns)
+ goto fail_free_ms_iocb;
}
- return(status);
+ return 0;
+
+fail_free_ms_iocb:
+ dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
+ ha->ms_iocb = NULL;
+ ha->ms_iocb_dma = 0;
+fail_free_nvram:
+ kfree(ha->nvram);
+ ha->nvram = NULL;
+fail_free_srb_mempool:
+ mempool_destroy(ha->srb_mempool);
+ ha->srb_mempool = NULL;
+fail_free_s_dma_pool:
+ dma_pool_destroy(ha->s_dma_pool);
+ ha->s_dma_pool = NULL;
+fail_free_init_cb:
+ dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb,
+ ha->init_cb_dma);
+ ha->init_cb = NULL;
+ ha->init_cb_dma = 0;
+fail_free_gid_list:
+ dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
+ ha->gid_list_dma);
+ ha->gid_list = NULL;
+ ha->gid_list_dma = 0;
+fail_free_response_ring:
+ dma_free_coherent(&ha->pdev->dev, (ha->response_q_length + 1) *
+ sizeof(response_t), ha->response_ring, ha->response_dma);
+ ha->response_ring = NULL;
+ ha->response_dma = 0;
+fail_free_request_ring:
+ dma_free_coherent(&ha->pdev->dev, (ha->request_q_length + 1) *
+ sizeof(request_t), ha->request_ring, ha->request_dma);
+ ha->request_ring = NULL;
+ ha->request_dma = 0;
+fail:
+ return -ENOMEM;
}
/*
struct list_head *fcpl, *fcptemp;
fc_port_t *fcport;
- if (ha == NULL) {
- /* error */
- DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__));
- return;
- }
-
- /* free sp pool */
- qla2x00_free_sp_pool(ha);
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
if (ha->fce)
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce,
(ha->request_q_length + 1) * sizeof(request_t),
ha->request_ring, ha->request_dma);
+ ha->srb_mempool = NULL;
ha->eft = NULL;
ha->eft_dma = 0;
ha->sns_cmd = NULL;
kfree(ha->nvram);
}
-/*
- * qla2x00_allocate_sp_pool
- * This routine is called during initialization to allocate
- * memory for local srb_t.
- *
- * Input:
- * ha = adapter block pointer.
- *
- * Context:
- * Kernel context.
- */
-static int
-qla2x00_allocate_sp_pool(scsi_qla_host_t *ha)
+struct qla_work_evt *
+qla2x00_alloc_work(struct scsi_qla_host *ha, enum qla_work_type type,
+ int locked)
{
- int rval;
+ struct qla_work_evt *e;
- rval = QLA_SUCCESS;
- ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
- if (ha->srb_mempool == NULL) {
- qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n");
- rval = QLA_FUNCTION_FAILED;
- }
- return (rval);
+ e = kzalloc(sizeof(struct qla_work_evt), locked ? GFP_ATOMIC:
+ GFP_KERNEL);
+ if (!e)
+ return NULL;
+
+ INIT_LIST_HEAD(&e->list);
+ e->type = type;
+ e->flags = QLA_EVT_FLAG_FREE;
+ return e;
+}
+
+int
+qla2x00_post_work(struct scsi_qla_host *ha, struct qla_work_evt *e, int locked)
+{
+ unsigned long flags;
+
+ if (!locked)
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ list_add_tail(&e->list, &ha->work_list);
+ qla2xxx_wake_dpc(ha);
+ if (!locked)
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return QLA_SUCCESS;
+}
+
+int
+qla2x00_post_aen_work(struct scsi_qla_host *ha, enum fc_host_event_code code,
+ u32 data)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(ha, QLA_EVT_AEN, 1);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.aen.code = code;
+ e->u.aen.data = data;
+ return qla2x00_post_work(ha, e, 1);
+}
+
+int
+qla2x00_post_hwe_work(struct scsi_qla_host *ha, uint16_t code, uint16_t d1,
+ uint16_t d2, uint16_t d3)
+{
+ struct qla_work_evt *e;
+
+ e = qla2x00_alloc_work(ha, QLA_EVT_HWE_LOG, 1);
+ if (!e)
+ return QLA_FUNCTION_FAILED;
+
+ e->u.hwe.code = code;
+ e->u.hwe.d1 = d1;
+ e->u.hwe.d2 = d2;
+ e->u.hwe.d3 = d3;
+ return qla2x00_post_work(ha, e, 1);
}
-/*
- * This routine frees all adapter allocated memory.
- *
- */
static void
-qla2x00_free_sp_pool( scsi_qla_host_t *ha)
+qla2x00_do_work(struct scsi_qla_host *ha)
{
- if (ha->srb_mempool) {
- mempool_destroy(ha->srb_mempool);
- ha->srb_mempool = NULL;
+ struct qla_work_evt *e;
+
+ spin_lock_irq(&ha->hardware_lock);
+ while (!list_empty(&ha->work_list)) {
+ e = list_entry(ha->work_list.next, struct qla_work_evt, list);
+ list_del_init(&e->list);
+ spin_unlock_irq(&ha->hardware_lock);
+
+ switch (e->type) {
+ case QLA_EVT_AEN:
+ fc_host_post_event(ha->host, fc_get_event_number(),
+ e->u.aen.code, e->u.aen.data);
+ break;
+ case QLA_EVT_HWE_LOG:
+ qla2xxx_hw_event_log(ha, e->u.hwe.code, e->u.hwe.d1,
+ e->u.hwe.d2, e->u.hwe.d3);
+ break;
+ }
+ if (e->flags & QLA_EVT_FLAG_FREE)
+ kfree(e);
+ spin_lock_irq(&ha->hardware_lock);
}
+ spin_unlock_irq(&ha->hardware_lock);
}
/**************************************************************************
fc_port_t *fcport;
uint8_t status;
uint16_t next_loopid;
+ struct scsi_qla_host *vha;
+ int i;
+
ha = (scsi_qla_host_t *)data;
continue;
}
+ qla2x00_do_work(ha);
+
if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
DEBUG(printk("scsi(%ld): dpc: sched "
}
clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
}
+
+ for_each_mapped_vp_idx(ha, i) {
+ list_for_each_entry(vha, &ha->vp_list,
+ vp_list) {
+ if (i == vha->vp_idx) {
+ set_bit(ISP_ABORT_NEEDED,
+ &vha->dpc_flags);
+ break;
+ }
+ }
+ }
+
DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n",
ha->host_no));
}
if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, &ha->dpc_flags))
qla2x00_update_fcports(ha);
- if (test_and_clear_bit(LOOP_RESET_NEEDED, &ha->dpc_flags)) {
- DEBUG(printk("scsi(%ld): dpc: sched loop_reset()\n",
- ha->host_no));
- qla2x00_loop_reset(ha);
- }
-
if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
(!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
ha->host_no));
}
- if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) &&
- atomic_read(&ha->loop_state) != LOOP_DOWN) {
-
- clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags);
- DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n",
- ha->host_no));
-
- set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
-
- DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n",
- ha->host_no));
- }
-
if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n",
ha->host_no));
}
- if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) {
-
- DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n",
- ha->host_no));
-
- qla2x00_rescan_fcports(ha);
-
- DEBUG(printk("scsi(%ld): Rescan flagged fcports..."
- "end.\n",
- ha->host_no));
- }
-
if (!ha->interrupts_on)
ha->isp_ops->enable_intrs(ha);
set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags);
start_dpc++;
- if (!(ha->device_flags & DFLG_NO_CABLE)) {
+ if (!(ha->device_flags & DFLG_NO_CABLE) &&
+ !ha->parent) {
DEBUG(printk("scsi(%ld): Loop down - "
"aborting ISP.\n",
ha->host_no));
/* Schedule the DPC routine if needed */
if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
- test_bit(LOOP_RESET_NEEDED, &ha->dpc_flags) ||
test_bit(FCPORT_UPDATE_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) ||
blob = &qla_fw_blobs[FW_ISP2300];
} else if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
blob = &qla_fw_blobs[FW_ISP2322];
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ } else if (IS_QLA24XX_TYPE(ha)) {
blob = &qla_fw_blobs[FW_ISP24XX];
} else if (IS_QLA25XX(ha)) {
blob = &qla_fw_blobs[FW_ISP25XX];
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
+ { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
MODULE_FIRMWARE(FW_FILE_ISP2300);
MODULE_FIRMWARE(FW_FILE_ISP2322);
MODULE_FIRMWARE(FW_FILE_ISP24XX);
+MODULE_FIRMWARE(FW_FILE_ISP25XX);