X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fqla2xxx%2Fqla_init.c;h=a4a6a146fccdbc630bddb08297caf9339f1e6b43;hb=a13d8ac057705c479b8bf15e5303f18f899502f9;hp=3ec6eaca96d467030f2a82d29d9fc1b63eb168a3;hpb=124f85e6cc0290a85adb7e14cd90e96105f4f9fb;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3ec6eac..a4a6a14 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -20,7 +20,6 @@ * QLogic ISP2x00 Hardware Support Function Prototypes. */ static int qla2x00_isp_firmware(scsi_qla_host_t *); -static void qla2x00_resize_request_q(scsi_qla_host_t *); static int qla2x00_setup_chip(scsi_qla_host_t *); static int qla2x00_init_rings(scsi_qla_host_t *); static int qla2x00_fw_ready(scsi_qla_host_t *); @@ -61,8 +60,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) int rval; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + /* Clear adapter flags. */ vha->flags.online = 0; + ha->flags.chip_reset_done = 0; vha->flags.reset_active = 0; atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); atomic_set(&vha->loop_state, LOOP_DOWN); @@ -70,7 +71,6 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) vha->dpc_flags = 0; vha->flags.management_server_logged_in = 0; vha->marker_needed = 0; - ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); @@ -131,6 +131,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) } } rval = qla2x00_init_rings(vha); + ha->flags.chip_reset_done = 1; return (rval); } @@ -512,7 +513,6 @@ qla2x00_reset_chip(scsi_qla_host_t *vha) static inline void qla24xx_reset_risc(scsi_qla_host_t *vha) { - int hw_evt = 0; unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; @@ -542,8 +542,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) d2 = (uint32_t) RD_REG_WORD(®->mailbox0); barrier(); } - if (cnt == 0) - hw_evt = 1; /* Wait for soft-reset to complete. */ d2 = RD_REG_DWORD(®->ctrl_status); @@ -636,7 +634,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) goto chip_diag_failed; DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n", - ha->host_no)); + vha->host_no)); /* Reset RISC processor. */ WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); @@ -657,7 +655,7 @@ qla2x00_chip_diag(scsi_qla_host_t *vha) goto chip_diag_failed; /* Check product ID of chip */ - DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no)); + DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no)); mb[1] = RD_MAILBOX_REG(ha, reg, 1); mb[2] = RD_MAILBOX_REG(ha, reg, 2); @@ -778,16 +776,18 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - fixed_size = IS_QLA25XX(ha) ? - offsetof(struct qla25xx_fw_dump, ext_mem) : - offsetof(struct qla24xx_fw_dump, ext_mem); + if (IS_QLA81XX(ha)) + fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); + else if (IS_QLA25XX(ha)) + fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem); + else + fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) mq_size = sizeof(struct qla2xxx_mq_chain); - /* Allocate memory for Fibre Channel Event Buffer. */ - if (!IS_QLA25XX(ha)) + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)) goto try_eft; tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, @@ -813,7 +813,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", FCE_SIZE / 1024); - fce_size = sizeof(struct qla2xxx_fce_chain) + EFT_SIZE; + fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; ha->flags.fce_enabled = 1; ha->fce_dma = tc_dma; ha->fce = tc; @@ -849,8 +849,9 @@ cont_alloc: rsp_q_size = rsp->length * sizeof(response_t); dump_size = offsetof(struct qla2xxx_fw_dump, isp); - dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + - mq_size + eft_size + fce_size; + dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size; + ha->chain_offset = dump_size; + dump_size += mq_size + fce_size; ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { @@ -889,62 +890,6 @@ cont_alloc: } /** - * qla2x00_resize_request_q() - Resize request queue given available ISP memory. - * @ha: HA context - * - * Returns 0 on success. - */ -static void -qla2x00_resize_request_q(scsi_qla_host_t *vha) -{ - int rval; - uint16_t fw_iocb_cnt = 0; - uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM; - dma_addr_t request_dma; - request_t *request_ring; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* Valid only on recent ISPs. */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return; - - /* Retrieve IOCB counts available to the firmware. */ - rval = qla2x00_get_resource_cnts(vha, NULL, NULL, NULL, &fw_iocb_cnt, - &ha->max_npiv_vports); - if (rval) - return; - /* No point in continuing if current settings are sufficient. */ - if (fw_iocb_cnt < 1024) - return; - if (req->length >= request_q_length) - return; - - /* Attempt to claim larger area for request queue. */ - request_ring = dma_alloc_coherent(&ha->pdev->dev, - (request_q_length + 1) * sizeof(request_t), &request_dma, - GFP_KERNEL); - if (request_ring == NULL) - return; - - /* Resize successful, report extensions. */ - qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n", - (ha->fw_memory_size + 1) / 1024); - qla_printk(KERN_INFO, ha, "Resizing request queue depth " - "(%d -> %d)...\n", req->length, request_q_length); - - /* Clear old allocations. */ - dma_free_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), req->ring, - req->dma); - - /* Begin using larger queue. */ - req->length = request_q_length; - req->ring = request_ring; - req->dma = request_dma; -} - -/** * qla2x00_setup_chip() - Load and start RISC firmware. * @ha: HA context * @@ -958,6 +903,7 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; unsigned long flags; + uint16_t fw_major_version; if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { /* Disable SRAM, Instruction RAM and GP RAM parity. */ @@ -981,12 +927,15 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) rval = qla2x00_execute_fw(vha, srisc_address); /* Retrieve firmware information. */ - if (rval == QLA_SUCCESS && ha->fw_major_version == 0) { + if (rval == QLA_SUCCESS) { + fw_major_version = ha->fw_major_version; qla2x00_get_fw_version(vha, &ha->fw_major_version, &ha->fw_minor_version, &ha->fw_subminor_version, - &ha->fw_attributes, &ha->fw_memory_size); + &ha->fw_attributes, &ha->fw_memory_size, + ha->mpi_version, &ha->mpi_capabilities, + ha->phy_version); ha->flags.npiv_supported = 0; if (IS_QLA2XXX_MIDTYPE(ha) && (ha->fw_attributes & BIT_2)) { @@ -997,9 +946,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; } - qla2x00_resize_request_q(vha); + qla2x00_get_resource_cnts(vha, NULL, + &ha->fw_xcb_count, NULL, NULL, + &ha->max_npiv_vports); - if (ql2xallocfwdump) + if (!fw_major_version && ql2xallocfwdump) qla2x00_alloc_fw_dump(vha); } } else { @@ -1022,6 +973,21 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); } + if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) { + uint32_t size; + + rval = qla81xx_fac_get_sector_size(vha, &size); + if (rval == QLA_SUCCESS) { + ha->flags.fac_supported = 1; + ha->fdt_block_size = size << 2; + } else { + qla_printk(KERN_ERR, ha, + "Unsupported FAC firmware (%d.%02d.%02d).\n", + ha->fw_major_version, ha->fw_minor_version, + ha->fw_subminor_version); + } + } + if (rval) { DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n", vha->host_no)); @@ -1045,12 +1011,14 @@ qla2x00_init_response_q_entries(struct rsp_que *rsp) uint16_t cnt; response_t *pkt; + rsp->ring_ptr = rsp->ring; + rsp->ring_index = 0; + rsp->status_srb = NULL; pkt = rsp->ring_ptr; for (cnt = 0; cnt < rsp->length; cnt++) { pkt->signature = RESPONSE_PROCESSED; pkt++; } - } /** @@ -1208,7 +1176,7 @@ qla24xx_config_rings(struct scsi_qla_host *vha) if (ha->flags.msix_enabled) { msix = &ha->msix_entries[1]; DEBUG2_17(printk(KERN_INFO - "Reistering vector 0x%x for base que\n", msix->entry)); + "Registering vector 0x%x for base que\n", msix->entry)); icb->msix = cpu_to_le16(msix->entry); } /* Use alternate PCI bus number */ @@ -1220,9 +1188,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_18); - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); + icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22); icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); - ha->rsp_q_map[0]->options = icb->firmware_options_2; WRT_REG_DWORD(®->isp25mq.req_q_in, 0); WRT_REG_DWORD(®->isp25mq.req_q_out, 0); @@ -1252,35 +1219,45 @@ qla2x00_init_rings(scsi_qla_host_t *vha) { int rval; unsigned long flags = 0; - int cnt; + int cnt, que; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; + struct req_que *req; + struct rsp_que *rsp; + struct scsi_qla_host *vp; struct mid_init_cb_24xx *mid_init_cb = (struct mid_init_cb_24xx *) ha->init_cb; spin_lock_irqsave(&ha->hardware_lock, flags); /* Clear outstanding commands array. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) - req->outstanding_cmds[cnt] = NULL; + for (que = 0; que < ha->max_req_queues; que++) { + req = ha->req_q_map[que]; + if (!req) + continue; + for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) + req->outstanding_cmds[cnt] = NULL; - req->current_outstanding_cmd = 0; + req->current_outstanding_cmd = 1; - /* Clear RSCN queue. */ - vha->rscn_in_ptr = 0; - vha->rscn_out_ptr = 0; - - /* Initialize firmware. */ - req->ring_ptr = req->ring; - req->ring_index = 0; - req->cnt = req->length; - rsp->ring_ptr = rsp->ring; - rsp->ring_index = 0; + /* Initialize firmware. */ + req->ring_ptr = req->ring; + req->ring_index = 0; + req->cnt = req->length; + } - /* Initialize response queue entries */ - qla2x00_init_response_q_entries(rsp); + for (que = 0; que < ha->max_rsp_queues; que++) { + rsp = ha->rsp_q_map[que]; + if (!rsp) + continue; + /* Initialize response queue entries */ + qla2x00_init_response_q_entries(rsp); + } + /* Clear RSCN queue. */ + list_for_each_entry(vp, &ha->vp_list, list) { + vp->rscn_in_ptr = 0; + vp->rscn_out_ptr = 0; + } ha->isp_ops->config_rings(vha); spin_unlock_irqrestore(&ha->hardware_lock, flags); @@ -1290,10 +1267,17 @@ qla2x00_init_rings(scsi_qla_host_t *vha) DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no)); - if (ha->flags.npiv_supported) + if (ha->flags.npiv_supported) { + if (ha->operating_mode == LOOP) + ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); + } - mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + if (IS_FWI2_CAPABLE(ha)) { + mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + mid_init_cb->init_cb.execution_throttle = + cpu_to_le16(ha->fw_xcb_count); + } rval = qla2x00_init_firmware(vha, ha->init_cb_size); if (rval) { @@ -1554,6 +1538,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, char *st, *en; uint16_t index; struct qla_hw_data *ha = vha->hw; + int use_tbl = !IS_QLA25XX(ha) && IS_QLA81XX(ha); if (memcmp(model, BINZERO, len) != 0) { strncpy(ha->model_number, model, len); @@ -1566,14 +1551,16 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, } index = (ha->pdev->subsystem_device & 0xff); - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + if (use_tbl && + ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) strncpy(ha->model_desc, qla2x00_model_name[index * 2 + 1], sizeof(ha->model_desc) - 1); } else { index = (ha->pdev->subsystem_device & 0xff); - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && + if (use_tbl && + ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) { strcpy(ha->model_number, qla2x00_model_name[index * 2]); @@ -1967,7 +1954,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; atomic_set(&fcport->state, FCS_UNCONFIGURED); - fcport->flags = FCF_RLC_SUPPORT; fcport->supported_classes = FC_COS_UNSPECIFIED; return fcport; @@ -2124,7 +2110,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) goto cleanup_allocation; DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n", - ha->host_no, entries)); + vha->host_no, entries)); DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list, entries * sizeof(struct gid_list_info))); @@ -2149,7 +2135,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) vha->host_no, fcport->loop_id)); atomic_set(&fcport->state, FCS_DEVICE_LOST); - fcport->flags &= ~FCF_FARP_DONE; } } @@ -2206,8 +2191,7 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) WWN_SIZE)) continue; - fcport->flags &= ~(FCF_FABRIC_DEVICE | - FCF_PERSISTENT_BOUND); + fcport->flags &= ~FCF_FABRIC_DEVICE; fcport->loop_id = new_fcport->loop_id; fcport->port_type = new_fcport->port_type; fcport->d_id.b24 = new_fcport->d_id.b24; @@ -2220,7 +2204,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) if (!found) { /* New device, add to fcports list. */ - new_fcport->flags &= ~FCF_PERSISTENT_BOUND; if (vha->vp_idx) { new_fcport->vha = vha; new_fcport->vp_idx = vha->vp_idx; @@ -2253,11 +2236,6 @@ cleanup_allocation: "rval=%x\n", vha->host_no, rval)); } - if (found_devs) { - vha->device_flags |= DFLG_LOCAL_DEVICES; - vha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES; - } - return (rval); } @@ -2592,6 +2570,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, port_id_t wrap, nxt_d_id; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); + struct scsi_qla_host *tvp; rval = QLA_SUCCESS; @@ -2691,7 +2670,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, /* Bypass virtual ports of the same host. */ found = 0; if (ha->num_vhosts) { - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (new_fcport->d_id.b24 == vp->d_id.b24) { found = 1; break; @@ -2742,7 +2721,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, fcport->loop_id = FC_NO_LOOP_ID; fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); - fcport->flags &= ~FCF_PERSISTENT_BOUND; break; } @@ -2785,9 +2763,6 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, kfree(swl); kfree(new_fcport); - if (!list_empty(new_fcports)) - vha->device_flags |= DFLG_FABRIC_DEVICES; - return (rval); } @@ -2814,6 +2789,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) uint16_t first_loop_id; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; + struct scsi_qla_host *tvp; rval = QLA_SUCCESS; @@ -2838,7 +2814,7 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) /* Check for loop ID being already in use. */ found = 0; fcport = NULL; - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { list_for_each_entry(fcport, &vp->vp_fcports, list) { if (fcport->loop_id == dev->loop_id && fcport != dev) { @@ -2969,7 +2945,6 @@ qla2x00_device_resync(scsi_qla_host_t *vha) 0, 0); } } - fcport->flags &= ~FCF_FARP_DONE; } } return (rval); @@ -3205,9 +3180,14 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) { int rval = QLA_SUCCESS; uint32_t wait_time; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; + struct req_que *req; + struct rsp_que *rsp; + + if (ql2xmultique_tag) + req = vha->hw->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; atomic_set(&vha->loop_state, LOOP_UPDATE); clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); @@ -3273,10 +3253,12 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) uint8_t status = 0; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *vp; + struct scsi_qla_host *tvp; struct req_que *req = ha->req_q_map[0]; if (vha->flags.online) { vha->flags.online = 0; + ha->flags.chip_reset_done = 0; clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); ha->qla_stats.total_isp_aborts++; @@ -3288,7 +3270,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); qla2x00_mark_all_devices_lost(vha, 0); - list_for_each_entry(vp, &ha->vp_list, list) + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) qla2x00_mark_all_devices_lost(vp, 0); } else { if (!atomic_read(&vha->loop_down_timer)) @@ -3385,7 +3367,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): succeeded.\n", vha->host_no)); - list_for_each_entry(vp, &ha->vp_list, list) { + list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { if (vp->vp_idx) qla2x00_vp_abort_isp(vp); } @@ -3410,7 +3392,7 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) static int qla2x00_restart_isp(scsi_qla_host_t *vha) { - uint8_t status = 0; + int status = 0; uint32_t wait_time; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; @@ -3426,6 +3408,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) if (!status && !(status = qla2x00_init_rings(vha))) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); + ha->flags.chip_reset_done = 1; /* Initialize the queues in use */ qla25xx_init_queues(ha); @@ -3470,11 +3453,11 @@ qla25xx_init_queues(struct qla_hw_data *ha) int ret = -1; int i; - for (i = 1; i < ha->max_queues; i++) { + for (i = 1; i < ha->max_rsp_queues; i++) { rsp = ha->rsp_q_map[i]; if (rsp) { rsp->options &= ~BIT_0; - ret = qla25xx_init_rsp_que(base_vha, rsp, rsp->options); + ret = qla25xx_init_rsp_que(base_vha, rsp); if (ret != QLA_SUCCESS) DEBUG2_17(printk(KERN_WARNING "%s Rsp que:%d init failed\n", __func__, @@ -3484,17 +3467,20 @@ qla25xx_init_queues(struct qla_hw_data *ha) "%s Rsp que:%d inited\n", __func__, rsp->id)); } + } + for (i = 1; i < ha->max_req_queues; i++) { req = ha->req_q_map[i]; if (req) { + /* Clear outstanding commands array. */ req->options &= ~BIT_0; - ret = qla25xx_init_req_que(base_vha, req, req->options); + ret = qla25xx_init_req_que(base_vha, req); if (ret != QLA_SUCCESS) DEBUG2_17(printk(KERN_WARNING "%s Req que:%d init failed\n", __func__, req->id)); else DEBUG2_17(printk(KERN_WARNING - "%s Rsp que:%d inited\n", __func__, + "%s Req que:%d inited\n", __func__, req->id)); } } @@ -3542,6 +3528,9 @@ qla24xx_reset_adapter(scsi_qla_host_t *vha) WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); RD_REG_DWORD(®->hccr); spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (IS_NOPOLLING_TYPE(ha)) + ha->isp_ops->enable_intrs(ha); } /* On sparc systems, obtain port and node WWN from firmware @@ -3605,7 +3594,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) chksum += le32_to_cpu(*dptr++); - DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no)); DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size)); /* Bad NVRAM data, set defaults parameters. */ @@ -3827,6 +3816,10 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr) uint32_t i; struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; + + qla_printk(KERN_INFO, ha, + "FW: Loading from flash (%x)...\n", ha->flt_region_fw); + rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; @@ -4002,8 +3995,8 @@ fail_fw_integrity: return QLA_FUNCTION_FAILED; } -int -qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) +static int +qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) { int rval; int segments, fragment; @@ -4023,12 +4016,12 @@ qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) qla_printk(KERN_ERR, ha, "Firmware images can be retrieved " "from: " QLA_FW_URL ".\n"); - /* Try to load RISC code from flash. */ - qla_printk(KERN_ERR, ha, "Attempting to load (potentially " - "outdated) firmware from flash.\n"); - return qla24xx_load_risc_flash(vha, srisc_addr); + return QLA_FUNCTION_FAILED; } + qla_printk(KERN_INFO, ha, + "FW: Loading via request-firmware...\n"); + rval = QLA_SUCCESS; segments = FA_RISC_CODE_SEGMENTS; @@ -4113,6 +4106,40 @@ fail_fw_integrity: return QLA_FUNCTION_FAILED; } +int +qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) +{ + int rval; + + /* + * FW Load priority: + * 1) Firmware via request-firmware interface (.bin file). + * 2) Firmware residing in flash. + */ + rval = qla24xx_load_risc_blob(vha, srisc_addr); + if (rval == QLA_SUCCESS) + return rval; + + return qla24xx_load_risc_flash(vha, srisc_addr); +} + +int +qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) +{ + int rval; + + /* + * FW Load priority: + * 1) Firmware residing in flash. + * 2) Firmware via request-firmware interface (.bin file). + */ + rval = qla24xx_load_risc_flash(vha, srisc_addr); + if (rval == QLA_SUCCESS) + return rval; + + return qla24xx_load_risc_blob(vha, srisc_addr); +} + void qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha) { @@ -4145,13 +4172,19 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) uint16_t mb[MAILBOX_REGISTER_COUNT]; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; + struct req_que *req; + struct rsp_que *rsp; if (!vha->vp_idx) return -EINVAL; rval = qla2x00_fw_ready(base_vha); + if (ql2xmultique_tag) + req = ha->req_q_map[0]; + else + req = vha->req; + rsp = req->rsp; + if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); @@ -4250,3 +4283,266 @@ qla84xx_init_chip(scsi_qla_host_t *vha) return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: QLA_SUCCESS; } + +/* 81XX Support **************************************************************/ + +int +qla81xx_nvram_config(scsi_qla_host_t *vha) +{ + int rval; + struct init_cb_81xx *icb; + struct nvram_81xx *nv; + uint32_t *dptr; + uint8_t *dptr1, *dptr2; + uint32_t chksum; + uint16_t cnt; + struct qla_hw_data *ha = vha->hw; + + rval = QLA_SUCCESS; + icb = (struct init_cb_81xx *)ha->init_cb; + nv = ha->nvram; + + /* Determine NVRAM starting address. */ + ha->nvram_size = sizeof(struct nvram_81xx); + ha->vpd_size = FA_NVRAM_VPD_SIZE; + + /* Get VPD data into cache */ + ha->vpd = ha->nvram + VPD_OFFSET; + ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, + ha->vpd_size); + + /* Get NVRAM data into cache and calculate checksum. */ + ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, + ha->nvram_size); + dptr = (uint32_t *)nv; + for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) + chksum += le32_to_cpu(*dptr++); + + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no)); + DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size)); + + /* Bad NVRAM data, set defaults parameters. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' + || nv->id[3] != ' ' || + nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { + /* Reset NVRAM data. */ + qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], + le16_to_cpu(nv->nvram_version)); + qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " + "invalid -- WWPN) defaults.\n"); + + /* + * Set default initialization control block. + */ + memset(nv, 0, ha->nvram_size); + nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); + nv->version = __constant_cpu_to_le16(ICB_VERSION); + nv->frame_payload_size = __constant_cpu_to_le16(2048); + nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); + nv->exchange_count = __constant_cpu_to_le16(0); + nv->port_name[0] = 0x21; + nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); + nv->port_name[2] = 0x00; + nv->port_name[3] = 0xe0; + nv->port_name[4] = 0x8b; + nv->port_name[5] = 0x1c; + nv->port_name[6] = 0x55; + nv->port_name[7] = 0x86; + nv->node_name[0] = 0x20; + nv->node_name[1] = 0x00; + nv->node_name[2] = 0x00; + nv->node_name[3] = 0xe0; + nv->node_name[4] = 0x8b; + nv->node_name[5] = 0x1c; + nv->node_name[6] = 0x55; + nv->node_name[7] = 0x86; + nv->login_retry_count = __constant_cpu_to_le16(8); + nv->interrupt_delay_timer = __constant_cpu_to_le16(0); + nv->login_timeout = __constant_cpu_to_le16(0); + nv->firmware_options_1 = + __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); + nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); + nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); + nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); + nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); + nv->efi_parameters = __constant_cpu_to_le32(0); + nv->reset_delay = 5; + nv->max_luns_per_target = __constant_cpu_to_le16(128); + nv->port_down_retry_count = __constant_cpu_to_le16(30); + nv->link_down_timeout = __constant_cpu_to_le16(30); + nv->enode_mac[0] = 0x01; + nv->enode_mac[1] = 0x02; + nv->enode_mac[2] = 0x03; + nv->enode_mac[3] = 0x04; + nv->enode_mac[4] = 0x05; + nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + + rval = 1; + } + + /* Reset Initialization control block */ + memset(icb, 0, sizeof(struct init_cb_81xx)); + + /* Copy 1st segment. */ + dptr1 = (uint8_t *)icb; + dptr2 = (uint8_t *)&nv->version; + cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version; + while (cnt--) + *dptr1++ = *dptr2++; + + icb->login_retry_count = nv->login_retry_count; + + /* Copy 2nd segment. */ + dptr1 = (uint8_t *)&icb->interrupt_delay_timer; + dptr2 = (uint8_t *)&nv->interrupt_delay_timer; + cnt = (uint8_t *)&icb->reserved_5 - + (uint8_t *)&icb->interrupt_delay_timer; + while (cnt--) + *dptr1++ = *dptr2++; + + memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac)); + /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */ + if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) { + icb->enode_mac[0] = 0x01; + icb->enode_mac[1] = 0x02; + icb->enode_mac[2] = 0x03; + icb->enode_mac[3] = 0x04; + icb->enode_mac[4] = 0x05; + icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + } + + /* Use extended-initialization control block. */ + memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb)); + + /* + * Setup driver NVRAM options. + */ + qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), + "QLE81XX"); + + /* Use alternate WWN? */ + if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { + memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); + memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); + } + + /* Prepare nodename */ + if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { + /* + * Firmware will apply the following mask if the nodename was + * not provided. + */ + memcpy(icb->node_name, icb->port_name, WWN_SIZE); + icb->node_name[0] &= 0xF0; + } + + /* Set host adapter parameters. */ + ha->flags.disable_risc_code_load = 0; + ha->flags.enable_lip_reset = 0; + ha->flags.enable_lip_full_login = + le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; + ha->flags.enable_target_reset = + le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; + ha->flags.enable_led_scheme = 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; + + ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & + (BIT_6 | BIT_5 | BIT_4)) >> 4; + + /* save HBA serial number */ + ha->serial0 = icb->port_name[5]; + ha->serial1 = icb->port_name[6]; + ha->serial2 = icb->port_name[7]; + memcpy(vha->node_name, icb->node_name, WWN_SIZE); + memcpy(vha->port_name, icb->port_name, WWN_SIZE); + + icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + + ha->retry_count = le16_to_cpu(nv->login_retry_count); + + /* Set minimum login_timeout to 4 seconds. */ + if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) + nv->login_timeout = cpu_to_le16(ql2xlogintimeout); + if (le16_to_cpu(nv->login_timeout) < 4) + nv->login_timeout = __constant_cpu_to_le16(4); + ha->login_timeout = le16_to_cpu(nv->login_timeout); + icb->login_timeout = nv->login_timeout; + + /* Set minimum RATOV to 100 tenths of a second. */ + ha->r_a_tov = 100; + + ha->loop_reset_delay = nv->reset_delay; + + /* Link Down Timeout = 0: + * + * When Port Down timer expires we will start returning + * I/O's to OS with "DID_NO_CONNECT". + * + * Link Down Timeout != 0: + * + * The driver waits for the link to come up after link down + * before returning I/Os to OS with "DID_NO_CONNECT". + */ + if (le16_to_cpu(nv->link_down_timeout) == 0) { + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); + } else { + ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout); + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - ha->link_down_timeout); + } + + /* Need enough time to try and get the port back. */ + ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count); + if (qlport_down_retry) + ha->port_down_retry_count = qlport_down_retry; + + /* Set login_retry_count */ + ha->login_retry_count = le16_to_cpu(nv->login_retry_count); + if (ha->port_down_retry_count == + le16_to_cpu(nv->port_down_retry_count) && + ha->port_down_retry_count > 3) + ha->login_retry_count = ha->port_down_retry_count; + else if (ha->port_down_retry_count > (int)ha->login_retry_count) + ha->login_retry_count = ha->port_down_retry_count; + if (ql2xloginretrycount) + ha->login_retry_count = ql2xloginretrycount; + + /* Enable ZIO. */ + if (!vha->flags.init_done) { + ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & + (BIT_3 | BIT_2 | BIT_1 | BIT_0); + ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? + le16_to_cpu(icb->interrupt_delay_timer): 2; + } + icb->firmware_options_2 &= __constant_cpu_to_le32( + ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); + vha->flags.process_response_queue = 0; + if (ha->zio_mode != QLA_ZIO_DISABLED) { + ha->zio_mode = QLA_ZIO_MODE_6; + + DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay " + "(%d us).\n", vha->host_no, ha->zio_mode, + ha->zio_timer * 100)); + qla_printk(KERN_INFO, ha, + "ZIO mode %d enabled; timer delay (%d us).\n", + ha->zio_mode, ha->zio_timer * 100); + + icb->firmware_options_2 |= cpu_to_le32( + (uint32_t)ha->zio_mode); + icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer); + vha->flags.process_response_queue = 1; + } + + if (rval) { + DEBUG2_3(printk(KERN_WARNING + "scsi(%ld): NVRAM configuration failed!\n", vha->host_no)); + } + return (rval); +} + +void +qla81xx_update_fw_options(scsi_qla_host_t *ha) +{ +}