diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_os.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 621 |
1 files changed, 455 insertions, 166 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0b12498..9000659 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2,7 +2,7 @@ * QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.6.x - * Copyright (C) 2003-2004 QLogic Corporation + * Copyright (C) 2003-2005 QLogic Corporation * (www.qlogic.com) * * This program is free software; you can redistribute it and/or modify it @@ -64,7 +64,7 @@ MODULE_PARM_DESC(ql2xplogiabsentdevice, int ql2xenablezio = 0; module_param(ql2xenablezio, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xenablezio, - "Option to enable ZIO:If 1 then enable it otherwise" + "Option to enable ZIO:If 1 then enable it otherwise" " use the default set in the NVRAM." " Default is 0 : disabled"); @@ -79,18 +79,25 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); +int ql2xfwloadbin; +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); /* - * SCSI host template entry points + * SCSI host template entry points */ static int qla2xxx_slave_configure(struct scsi_device * device); static int qla2xxx_slave_alloc(struct scsi_device *); static void qla2xxx_slave_destroy(struct scsi_device *); static int qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)); +static int qla24xx_queuecommand(struct scsi_cmnd *cmd, + 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_bus_reset(struct scsi_cmnd *); @@ -124,6 +131,28 @@ static struct scsi_host_template qla2x00_driver_template = { .max_sectors = 0xFFFF, }; +static struct scsi_host_template qla24xx_driver_template = { + .module = THIS_MODULE, + .name = "qla2xxx", + .queuecommand = qla24xx_queuecommand, + + .eh_abort_handler = qla2xxx_eh_abort, + .eh_device_reset_handler = qla2xxx_eh_device_reset, + .eh_bus_reset_handler = qla2xxx_eh_bus_reset, + .eh_host_reset_handler = qla2xxx_eh_host_reset, + + .slave_configure = qla2xxx_slave_configure, + + .slave_alloc = qla2xxx_slave_alloc, + .slave_destroy = qla2xxx_slave_destroy, + .this_id = -1, + .cmd_per_lun = 3, + .use_clustering = ENABLE_CLUSTERING, + .sg_tablesize = SG_ALL, + + .max_sectors = 0xFFFF, +}; + static struct scsi_transport_template *qla2xxx_transport_template = NULL; /* TODO Convert to inlines @@ -171,14 +200,13 @@ static uint8_t 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 srb_t *qla2x00_get_new_sp(scsi_qla_host_t *); static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *); void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *); /* -------------------------------------------------------------------------- */ static char * -qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str) +qla2x00_pci_info_str(struct scsi_qla_host *ha, char *str) { static char *pci_bus_modes[] = { "33", "66", "100", "133", @@ -200,11 +228,59 @@ qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str) return (str); } +static char * +qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str) +{ + static char *pci_bus_modes[] = { "33", "66", "100", "133", }; + uint32_t pci_bus; + int pcie_reg; + + pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); + if (pcie_reg) { + char lwstr[6]; + uint16_t pcie_lstat, lspeed, lwidth; + + pcie_reg += 0x12; + pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat); + lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3); + lwidth = (pcie_lstat & + (BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4; + + strcpy(str, "PCIe ("); + if (lspeed == 1) + strcat(str, "2.5Gb/s "); + else + strcat(str, "<unknown> "); + snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth); + strcat(str, lwstr); + + return str; + } + + strcpy(str, "PCI"); + pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8; + if (pci_bus == 0 || pci_bus == 8) { + strcat(str, " ("); + strcat(str, pci_bus_modes[pci_bus >> 3]); + } else { + strcat(str, "-X "); + if (pci_bus & BIT_2) + strcat(str, "Mode 2"); + else + strcat(str, "Mode 1"); + strcat(str, " ("); + strcat(str, pci_bus_modes[pci_bus & ~BIT_2]); + } + strcat(str, " MHz)"); + + return str; +} + char * -qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str) +qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str) { char un_str[10]; - + sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, ha->fw_minor_version, ha->fw_subminor_version); @@ -238,25 +314,45 @@ qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str) return (str); } -/************************************************************************** -* qla2x00_queuecommand -* -* Description: -* Queue a command to the controller. -* -* Input: -* cmd - pointer to Scsi cmd structure -* fn - pointer to Scsi done function -* -* Returns: -* 0 - Always -* -* Note: -* The mid-level driver tries to ensures that queuecommand never gets invoked -* concurrently with itself or the interrupt handler (although the -* interrupt handler may call this routine as part of request-completion -* handling). -**************************************************************************/ +char * +qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str) +{ + sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, + ha->fw_minor_version, + ha->fw_subminor_version); + + if (ha->fw_attributes & BIT_0) + strcat(str, "[Class 2] "); + if (ha->fw_attributes & BIT_1) + strcat(str, "[IP] "); + if (ha->fw_attributes & BIT_2) + strcat(str, "[Multi-ID] "); + if (ha->fw_attributes & BIT_13) + strcat(str, "[Experimental]"); + return str; +} + +static inline srb_t * +qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport, + struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +{ + srb_t *sp; + + sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); + if (!sp) + return sp; + + atomic_set(&sp->ref_count, 1); + sp->ha = ha; + sp->fcport = fcport; + sp->cmd = cmd; + sp->flags = 0; + CMD_SP(cmd) = (void *)sp; + cmd->scsi_done = done; + + return sp; +} + static int qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -281,18 +377,9 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) spin_unlock_irq(ha->host->host_lock); - /* Allocate a command packet from the "sp" pool. */ - if ((sp = qla2x00_get_new_sp(ha)) == NULL) { + sp = qla2x00_get_new_sp(ha, fcport, cmd, done); + if (!sp) goto qc_host_busy_lock; - } - - sp->ha = ha; - sp->fcport = fcport; - sp->cmd = cmd; - sp->flags = 0; - - CMD_SP(cmd) = (void *)sp; - cmd->scsi_done = done; rval = qla2x00_start_scsi(sp); if (rval != QLA_SUCCESS) @@ -314,7 +401,6 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) qc_host_busy_free_sp: qla2x00_sp_free_dma(ha, sp); - CMD_SP(cmd) = NULL; mempool_free(sp, ha->srb_mempool); qc_host_busy_lock: @@ -329,6 +415,60 @@ qc_fail_command: return 0; } + +static int +qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) +{ + scsi_qla_host_t *ha = to_qla_host(cmd->device->host); + fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; + srb_t *sp; + int rval; + + if (!fcport) { + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&ha->loop_state) == LOOP_DEAD) { + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + goto qc24_host_busy; + } + + spin_unlock_irq(ha->host->host_lock); + + sp = qla2x00_get_new_sp(ha, fcport, cmd, done); + if (!sp) + goto qc24_host_busy_lock; + + rval = qla24xx_start_scsi(sp); + if (rval != QLA_SUCCESS) + goto qc24_host_busy_free_sp; + + spin_lock_irq(ha->host->host_lock); + + return 0; + +qc24_host_busy_free_sp: + qla2x00_sp_free_dma(ha, sp); + mempool_free(sp, ha->srb_mempool); + +qc24_host_busy_lock: + spin_lock_irq(ha->host->host_lock); + +qc24_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; + +qc24_fail_command: + done(cmd); + + return 0; +} + + /* * qla2x00_eh_wait_on_command * Waits for the command to be returned by the Firmware for some @@ -367,14 +507,14 @@ qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) /* * qla2x00_wait_for_hba_online - * Wait till the HBA is online after going through + * Wait till the HBA is online after going through * <= MAX_RETRIES_OF_ISP_ABORT or * finally HBA is disabled ie marked offline * * Input: * ha - pointer to host adapter structure - * - * Note: + * + * Note: * Does context switching-Release SPIN_LOCK * (if any) before calling this routine. * @@ -382,13 +522,13 @@ qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) * Success (Adapter is online) : 0 * Failed (Adapter is offline/disabled) : 1 */ -static int +static int qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) { - int return_status; - unsigned long wait_online; + int return_status; + unsigned long wait_online; - wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); + 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) || @@ -396,8 +536,8 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) msleep(1000); } - if (ha->flags.online) - return_status = QLA_SUCCESS; + if (ha->flags.online) + return_status = QLA_SUCCESS; else return_status = QLA_FUNCTION_FAILED; @@ -409,27 +549,27 @@ qla2x00_wait_for_hba_online(scsi_qla_host_t *ha) /* * qla2x00_wait_for_loop_ready * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop - * to be in LOOP_READY state. + * to be in LOOP_READY state. * Input: * ha - pointer to host adapter structure - * - * Note: + * + * Note: * Does context switching-Release SPIN_LOCK * (if any) before calling this routine. - * + * * * Return: * Success (LOOP_READY) : 0 * Failed (LOOP_NOT_READY) : 1 */ -static inline int +static inline int qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) { int return_status = QLA_SUCCESS; unsigned long loop_timeout ; /* wait for 5 min at the max for loop to be ready */ - loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); + loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); while ((!atomic_read(&ha->loop_down_timer) && atomic_read(&ha->loop_state) == LOOP_DOWN) || @@ -440,7 +580,7 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha) break; } } - return (return_status); + return (return_status); } /************************************************************************** @@ -493,7 +633,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG3(qla2x00_print_scsi_cmd(cmd);) spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (qla2x00_abort_command(ha, sp)) { + if (ha->isp_ops.abort_command(ha, sp)) { DEBUG2(printk("%s(%ld): abort_command " "mbx failed.\n", __func__, ha->host_no)); } else { @@ -510,13 +650,13 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) /* Wait for the command to be returned. */ if (ret == SUCCESS) { if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) { - qla_printk(KERN_ERR, ha, + qla_printk(KERN_ERR, ha, "scsi(%ld:%d:%d): Abort handler timed out -- %lx " "%x.\n", ha->host_no, id, lun, serial, ret); } } - qla_printk(KERN_INFO, ha, + qla_printk(KERN_INFO, ha, "scsi(%ld:%d:%d): Abort command issued -- %lx %x.\n", ha->host_no, id, lun, serial, ret); @@ -531,7 +671,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) * * Input: * ha - pointer to scsi_qla_host structure. -* t - target +* t - target * Returns: * Either SUCCESS or FAILED. * @@ -580,7 +720,7 @@ qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t) * 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 +* attempt to use this value, even if you determine it is * non-null. * * Input: @@ -624,7 +764,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) #if defined(LOGOUT_AFTER_DEVICE_RESET) if (ret == SUCCESS) { if (fcport->flags & FC_FABRIC_DEVICE) { - qla2x00_fabric_logout(ha, fcport->loop_id); + ha->isp_ops.fabric_logout(ha, fcport->loop_id); qla2x00_mark_device_lost(ha, fcport); } } @@ -656,7 +796,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) "commands\n", __func__, ha->host_no)); qla_printk(KERN_INFO, ha, "%s: failed while waiting for commands\n", - __func__); + __func__); goto eh_dev_reset_done; } @@ -822,7 +962,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) /* * Fixme-may be dpc thread is active and processing - * loop_resync,so wait a while for it to + * loop_resync,so wait a while for it to * be completed and then issue big hammer.Otherwise * it may cause I/O failure as big hammer marks the * devices as lost kicking of the port_down_timer @@ -837,7 +977,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) goto eh_host_reset_lock; - } + } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); /* Waiting for our command in done_queue to be returned to OS.*/ @@ -883,7 +1023,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) } if (status == QLA_SUCCESS && - ((!ha->flags.enable_target_reset && + ((!ha->flags.enable_target_reset && !ha->flags.enable_lip_reset) || ha->flags.enable_lip_full_login)) { @@ -925,32 +1065,18 @@ static int qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport) { /* Abort Target command will clear Reservation */ - return qla2x00_abort_target(reset_fcport); + return ha->isp_ops.abort_target(reset_fcport); } static int qla2xxx_slave_alloc(struct scsi_device *sdev) { - scsi_qla_host_t *ha = to_qla_host(sdev->host); struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - fc_port_t *fcport; - int found; if (!rport) return -ENXIO; - found = 0; - list_for_each_entry(fcport, &ha->fcports, list) { - if (rport->port_name == - be64_to_cpu(*(uint64_t *)fcport->port_name)) { - found++; - break; - } - } - if (!found) - return -ENXIO; - - sdev->hostdata = fcport; + sdev->hostdata = rport->dd_data; return 0; } @@ -989,8 +1115,6 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha) { /* Assume 32bit DMA address */ ha->flags.enable_64bit_addressing = 0; - ha->calc_request_entries = qla2x00_calc_iocbs_32; - ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_32; /* * Given the two variants pci_set_dma_mask(), allow the compiler to @@ -999,12 +1123,12 @@ qla2x00_config_dma_addressing(scsi_qla_host_t *ha) if (sizeof(dma_addr_t) > 4) { if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { ha->flags.enable_64bit_addressing = 1; - ha->calc_request_entries = qla2x00_calc_iocbs_64; - ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_64; + ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64; + ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64; if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { - qla_printk(KERN_DEBUG, ha, + qla_printk(KERN_DEBUG, ha, "Failed to set 64 bit PCI consistent mask; " "using 32 bit.\n"); pci_set_consistent_dma_mask(ha->pdev, @@ -1087,6 +1211,61 @@ iospace_error_exit: return (-ENOMEM); } +static void +qla2x00_enable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->interrupts_on = 1; + /* enable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, ICR_EN_INT | ICR_EN_RISC); + RD_REG_WORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + +} + +static void +qla2x00_disable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->interrupts_on = 0; + /* disable risc and host interrupts */ + WRT_REG_WORD(®->ictrl, 0); + RD_REG_WORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +static void +qla24xx_enable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->interrupts_on = 1; + WRT_REG_DWORD(®->ictrl, ICRX_EN_RISC_INT); + RD_REG_DWORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + +static void +qla24xx_disable_intrs(scsi_qla_host_t *ha) +{ + unsigned long flags = 0; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->interrupts_on = 0; + WRT_REG_DWORD(®->ictrl, 0); + RD_REG_DWORD(®->ictrl); + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} + /* * PCI driver interface */ @@ -1105,8 +1284,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) if (pci_enable_device(pdev)) goto probe_out; - host = scsi_host_alloc(&qla2x00_driver_template, - sizeof(scsi_qla_host_t)); + host = scsi_host_alloc(brd_info->sht ? brd_info->sht: + &qla2x00_driver_template, sizeof(scsi_qla_host_t)); if (host == NULL) { printk(KERN_WARNING "qla2xxx: Couldn't allocate host from scsi layer!\n"); @@ -1128,18 +1307,41 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) if (ret) goto probe_failed; - /* Sanitize the information from PCI BIOS. */ - host->irq = pdev->irq; - qla_printk(KERN_INFO, ha, "Found an %s, irq %d, iobase 0x%p\n", ha->brd_info->isp_name, - host->irq, ha->iobase); + pdev->irq, ha->iobase); spin_lock_init(&ha->hardware_lock); ha->prev_topology = 0; ha->ports = MAX_BUSES; - + ha->init_cb_size = sizeof(init_cb_t); + + /* Assign ISP specific operations. */ + ha->isp_ops.pci_config = qla2100_pci_config; + ha->isp_ops.reset_chip = qla2x00_reset_chip; + ha->isp_ops.chip_diag = qla2x00_chip_diag; + ha->isp_ops.config_rings = qla2x00_config_rings; + ha->isp_ops.reset_adapter = qla2x00_reset_adapter; + ha->isp_ops.nvram_config = qla2x00_nvram_config; + ha->isp_ops.update_fw_options = qla2x00_update_fw_options; + ha->isp_ops.load_risc = qla2x00_load_risc; + ha->isp_ops.pci_info_str = qla2x00_pci_info_str; + ha->isp_ops.fw_version_str = qla2x00_fw_version_str; + ha->isp_ops.intr_handler = qla2100_intr_handler; + ha->isp_ops.enable_intrs = qla2x00_enable_intrs; + ha->isp_ops.disable_intrs = qla2x00_disable_intrs; + ha->isp_ops.abort_command = qla2x00_abort_command; + ha->isp_ops.abort_target = qla2x00_abort_target; + ha->isp_ops.fabric_login = qla2x00_login_fabric; + ha->isp_ops.fabric_logout = qla2x00_fabric_logout; + ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; + ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; + ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; + ha->isp_ops.read_nvram = qla2x00_read_nvram_data; + ha->isp_ops.write_nvram = qla2x00_write_nvram_data; + ha->isp_ops.fw_dump = qla2100_fw_dump; + ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; if (IS_QLA2100(ha)) { host->max_id = MAX_TARGETS_2100; ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; @@ -1147,18 +1349,57 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->response_q_length = RESPONSE_ENTRY_CNT_2100; ha->last_loop_id = SNS_LAST_LOOP_ID_2100; host->sg_tablesize = 32; + ha->gid_list_info_size = 4; } else if (IS_QLA2200(ha)) { host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; ha->request_q_length = REQUEST_ENTRY_CNT_2200; ha->response_q_length = RESPONSE_ENTRY_CNT_2100; ha->last_loop_id = SNS_LAST_LOOP_ID_2100; - } else /*if (IS_QLA2300(ha))*/ { + ha->gid_list_info_size = 4; + } else if (IS_QLA23XX(ha)) { host->max_id = MAX_TARGETS_2200; ha->mbx_count = MAILBOX_REGISTER_COUNT; ha->request_q_length = REQUEST_ENTRY_CNT_2200; ha->response_q_length = RESPONSE_ENTRY_CNT_2300; ha->last_loop_id = SNS_LAST_LOOP_ID_2300; + ha->isp_ops.pci_config = qla2300_pci_config; + ha->isp_ops.intr_handler = qla2300_intr_handler; + ha->isp_ops.fw_dump = qla2300_fw_dump; + ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; + ha->gid_list_info_size = 6; + } else if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { + host->max_id = MAX_TARGETS_2200; + ha->mbx_count = MAILBOX_REGISTER_COUNT; + 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->isp_ops.pci_config = qla24xx_pci_config; + ha->isp_ops.reset_chip = qla24xx_reset_chip; + ha->isp_ops.chip_diag = qla24xx_chip_diag; + ha->isp_ops.config_rings = qla24xx_config_rings; + 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; + ha->isp_ops.load_risc = qla24xx_load_risc_flash; + if (ql2xfwloadbin) + ha->isp_ops.load_risc = qla24xx_load_risc_hotplug; + 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; + ha->isp_ops.enable_intrs = qla24xx_enable_intrs; + ha->isp_ops.disable_intrs = qla24xx_disable_intrs; + ha->isp_ops.abort_command = qla24xx_abort_command; + ha->isp_ops.abort_target = qla24xx_abort_target; + ha->isp_ops.fabric_login = qla24xx_login_fabric; + ha->isp_ops.fabric_logout = qla24xx_fabric_logout; + ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb; + ha->isp_ops.read_nvram = qla24xx_read_nvram_data; + ha->isp_ops.write_nvram = qla24xx_write_nvram_data; + ha->isp_ops.fw_dump = qla24xx_fw_dump; + ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; + ha->gid_list_info_size = 8; } host->can_queue = ha->request_q_length + 128; @@ -1229,18 +1470,15 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) host->max_lun = MAX_LUNS; host->transportt = qla2xxx_transport_template; - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - ret = request_irq(host->irq, qla2100_intr_handler, - SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha); - else - ret = request_irq(host->irq, qla2300_intr_handler, - SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha); + ret = request_irq(pdev->irq, ha->isp_ops.intr_handler, + SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha); if (ret) { qla_printk(KERN_WARNING, ha, "Failed to reserve interrupt %d already in use.\n", - host->irq); + pdev->irq); goto probe_failed; } + host->irq = pdev->irq; /* Initialized the timer */ qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL); @@ -1248,30 +1486,33 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n", ha->host_no, ha)); - reg = ha->iobase; + ha->isp_ops.disable_intrs(ha); - /* Disable ISP interrupts. */ - qla2x00_disable_intrs(ha); - - /* Ensure mailbox registers are free. */ spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->semaphore, 0); - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); - - /* Enable proper parity */ - if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) { - if (IS_QLA2300(ha)) - /* SRAM parity */ - WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x1)); - else - /* SRAM, Instruction RAM and GP RAM parity */ - WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x7)); + reg = ha->iobase; + if (IS_QLA24XX(ha) || IS_QLA25XX(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); - /* Enable chip interrupts. */ - qla2x00_enable_intrs(ha); + ha->isp_ops.enable_intrs(ha); /* v2.19.5b6 */ /* @@ -1306,9 +1547,9 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) " 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, qla2x00_get_pci_info_str(ha, pci_info), - pci_name(ha->pdev), ha->flags.enable_64bit_addressing ? '+': '-', - ha->host_no, qla2x00_get_fw_version_str(ha, fw_str)); + 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)); /* Go with fc_rport registration. */ list_for_each_entry(fcport, &ha->fcports, list) @@ -1362,7 +1603,7 @@ qla2x00_free_device(scsi_qla_host_t *ha) /* turn-off interrupts on the card */ if (ha->interrupts_on) - qla2x00_disable_intrs(ha); + ha->isp_ops.disable_intrs(ha); /* Disable timer */ if (ha->timer_active) @@ -1414,7 +1655,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, { if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) fc_remote_port_block(fcport->rport); - /* + /* * We may need to retry the login, so don't change the state of the * port but do the retries. */ @@ -1459,7 +1700,7 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, * Context: */ void -qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) +qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) { fc_port_t *fcport; @@ -1576,7 +1817,7 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) continue; } - memset(ha->init_cb, 0, sizeof(init_cb_t)); + memset(ha->init_cb, 0, ha->init_cb_size); /* Get consistent memory allocated for Get Port Database cmd */ ha->iodesc_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, @@ -1788,10 +2029,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha) if (ha->fw_dump) free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order); - if (ha->fw_dump_buffer) - vfree(ha->fw_dump_buffer); + vfree(ha->fw_dump24); + + vfree(ha->fw_dump_buffer); ha->fw_dump = NULL; + ha->fw_dump24 = NULL; + ha->fw_dumped = 0; ha->fw_dump_reading = 0; ha->fw_dump_buffer = NULL; } @@ -1806,11 +2050,11 @@ qla2x00_mem_free(scsi_qla_host_t *ha) * * Context: * Kernel context. - * + * * Note: Sets the ref_count for non Null sp to one. */ static int -qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) +qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) { int rval; @@ -1826,10 +2070,10 @@ qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) /* * This routine frees all adapter allocated memory. - * + * */ static void -qla2x00_free_sp_pool( scsi_qla_host_t *ha) +qla2x00_free_sp_pool( scsi_qla_host_t *ha) { if (ha->srb_mempool) { mempool_destroy(ha->srb_mempool); @@ -1951,9 +2195,11 @@ qla2x00_do_dpc(void *data) if (fcport->flags & FCF_FABRIC_DEVICE) { if (fcport->flags & FCF_TAPE_PRESENT) - qla2x00_fabric_logout( - ha, - fcport->loop_id); + ha->isp_ops.fabric_logout( + ha, fcport->loop_id, + fcport->d_id.b.domain, + fcport->d_id.b.area, + fcport->d_id.b.al_pa); status = qla2x00_fabric_login( ha, fcport, &next_loopid); } else @@ -1966,7 +2212,7 @@ qla2x00_do_dpc(void *data) DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n", ha->host_no, fcport->loop_id)); - + fcport->port_login_retry_count = ha->port_down_retry_count * PORT_RETRY_TIME; atomic_set(&fcport->state, FCS_ONLINE); @@ -1997,7 +2243,7 @@ qla2x00_do_dpc(void *data) 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", @@ -2034,7 +2280,7 @@ qla2x00_do_dpc(void *data) } if (!ha->interrupts_on) - qla2x00_enable_intrs(ha); + ha->isp_ops.enable_intrs(ha); ha->dpc_active = 0; } /* End of while(1) */ @@ -2058,7 +2304,7 @@ qla2x00_do_dpc(void *data) * ha = adapter block pointer. */ static void -qla2x00_rst_aen(scsi_qla_host_t *ha) +qla2x00_rst_aen(scsi_qla_host_t *ha) { if (ha->flags.online && !ha->flags.reset_active && !atomic_read(&ha->loop_down_timer) && @@ -2076,25 +2322,6 @@ qla2x00_rst_aen(scsi_qla_host_t *ha) } } - -/* - * This routine will allocate SP from the free queue - * input: - * scsi_qla_host_t * - * output: - * srb_t * or NULL - */ -static srb_t * -qla2x00_get_new_sp(scsi_qla_host_t *ha) -{ - srb_t *sp; - - sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); - if (sp) - atomic_set(&sp->ref_count, 1); - return (sp); -} - static void qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp) { @@ -2110,6 +2337,7 @@ qla2x00_sp_free_dma(scsi_qla_host_t *ha, srb_t *sp) } sp->flags &= ~SRB_DMA_VALID; } + CMD_SP(cmd) = NULL; } void @@ -2119,7 +2347,6 @@ qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *sp) qla2x00_sp_free_dma(ha, sp); - CMD_SP(cmd) = NULL; mempool_free(sp, ha->srb_mempool); cmd->scsi_done(cmd); @@ -2148,7 +2375,7 @@ qla2x00_timer(scsi_qla_host_t *ha) * * Whenever, a port is in the LOST state we start decrementing its port * down timer every second until it reaches zero. Once it reaches zero - * the port it marked DEAD. + * the port it marked DEAD. */ t = 0; list_for_each_entry(fcport, &ha->fcports, list) { @@ -2160,11 +2387,11 @@ qla2x00_timer(scsi_qla_host_t *ha) if (atomic_read(&fcport->port_down_timer) == 0) continue; - if (atomic_dec_and_test(&fcport->port_down_timer) != 0) + if (atomic_dec_and_test(&fcport->port_down_timer) != 0) atomic_set(&fcport->state, FCS_DEVICE_DEAD); - + DEBUG(printk("scsi(%ld): fcport-%d - port retry count: " - "%d remainning\n", + "%d remaining\n", ha->host_no, t, atomic_read(&fcport->port_down_timer))); } @@ -2184,7 +2411,7 @@ qla2x00_timer(scsi_qla_host_t *ha) ha->host_no)); if (!IS_QLA2100(ha) && ha->link_down_timeout) - atomic_set(&ha->loop_state, LOOP_DEAD); + atomic_set(&ha->loop_state, LOOP_DEAD); /* Schedule an ISP abort to return any tape commands. */ spin_lock_irqsave(&ha->hardware_lock, cpu_flags); @@ -2227,7 +2454,7 @@ qla2x00_timer(scsi_qla_host_t *ha) set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); } } - DEBUG3(printk("scsi(%ld): Loop Down - seconds remainning %d\n", + DEBUG3(printk("scsi(%ld): Loop Down - seconds remaining %d\n", ha->host_no, atomic_read(&ha->loop_down_timer))); } @@ -2264,12 +2491,68 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) return -ETIMEDOUT; } +static struct qla_board_info qla_board_tbl[] = { + { + .drv_name = "qla2400", + .isp_name = "ISP2422", + .fw_fname = "ql2400_fw.bin", + .sht = &qla24xx_driver_template, + }, + { + .drv_name = "qla2400", + .isp_name = "ISP2432", + .fw_fname = "ql2400_fw.bin", + .sht = &qla24xx_driver_template, + }, +}; + +static struct pci_device_id qla2xxx_pci_tbl[] = { + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2422, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl[0], + }, + { + .vendor = PCI_VENDOR_ID_QLOGIC, + .device = PCI_DEVICE_ID_QLOGIC_ISP2432, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long)&qla_board_tbl[1], + }, + {0, 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, + (struct qla_board_info *)id->driver_data); +} + +static void __devexit +qla2xxx_remove_one(struct pci_dev *pdev) +{ + qla2x00_remove_one(pdev); +} + +static struct pci_driver qla2xxx_pci_driver = { + .name = "qla2xxx", + .id_table = qla2xxx_pci_tbl, + .probe = qla2xxx_probe_one, + .remove = __devexit_p(qla2xxx_remove_one), +}; + /** * qla2x00_module_init - Module initialization. **/ static int __init qla2x00_module_init(void) { + int ret = 0; + /* Allocate cache for SRBs. */ srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); @@ -2290,7 +2573,12 @@ qla2x00_module_init(void) return -ENODEV; printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); - return 0; + ret = pci_module_init(&qla2xxx_pci_driver); + if (ret) { + kmem_cache_destroy(srb_cachep); + fc_release_transport(qla2xxx_transport_template); + } + return ret; } /** @@ -2299,6 +2587,7 @@ qla2x00_module_init(void) static void __exit qla2x00_module_exit(void) { + pci_unregister_driver(&qla2xxx_pci_driver); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); } |