X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fscsi%2Fqla2xxx%2Fqla_init.c;h=44c0117c5d2bdccd4cbd8dac1ea4d294b5f3118e;hb=6d0525292ad13f17abcd4a21e488d5b667e90668;hp=d429e2f5c70e10b1fe5849eaab2cec1e7e5b27cd;hpb=587f4cae4a8ce1315c3def2229c2a912637269b6;p=linux-2.6 diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d429e2f5c7..44c0117c5d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -37,6 +37,9 @@ static int qla2x00_restart_isp(scsi_qla_host_t *); static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev); +static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); +static int qla84xx_init_chip(scsi_qla_host_t *); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -106,6 +109,15 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) rval = qla2x00_setup_chip(ha); if (rval) return (rval); + qla2xxx_get_flash_info(ha); + } + if (IS_QLA84XX(ha)) { + ha->cs84xx = qla84xx_get_chip(ha); + if (!ha->cs84xx) { + qla_printk(KERN_ERR, ha, + "Unable to configure ISP84XX.\n"); + return QLA_FUNCTION_FAILED; + } } rval = qla2x00_init_rings(ha); @@ -322,6 +334,8 @@ static int qla2x00_isp_firmware(scsi_qla_host_t *ha) { int rval; + uint16_t loop_id, topo, sw_cap; + uint8_t domain, area, al_pa; /* Assume loading risc code */ rval = QLA_FUNCTION_FAILED; @@ -333,6 +347,11 @@ qla2x00_isp_firmware(scsi_qla_host_t *ha) /* Verify checksum of loaded RISC code. */ rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address); + if (rval == QLA_SUCCESS) { + /* And, verify we are not in ROM code. */ + rval = qla2x00_get_adapter_id(ha, &loop_id, &al_pa, + &area, &domain, &topo, &sw_cap); + } } if (rval) { @@ -710,7 +729,7 @@ qla24xx_chip_diag(scsi_qla_host_t *ha) /* Perform RISC reset. */ qla24xx_reset_risc(ha); - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; + ha->fw_transfer_size = REQUEST_ENTRY_SIZE * ha->request_q_length; rval = qla2x00_mbx_reg_test(ha); if (rval) { @@ -756,42 +775,16 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); - /* Allocate memory for Extended Trace Buffer. */ - tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - qla_printk(KERN_WARNING, ha, "Unable to allocate " - "(%d KB) for EFT.\n", EFT_SIZE / 1024); - goto cont_alloc; - } - - memset(tc, 0, EFT_SIZE); - rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS); - if (rval) { - qla_printk(KERN_WARNING, ha, "Unable to initialize " - "EFT (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, - tc_dma); - goto cont_alloc; - } - - qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", - EFT_SIZE / 1024); - - eft_size = EFT_SIZE; - ha->eft_dma = tc_dma; - ha->eft = tc; - /* Allocate memory for Fibre Channel Event Buffer. */ if (!IS_QLA25XX(ha)) - goto cont_alloc; + goto try_eft; tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, GFP_KERNEL); if (!tc) { qla_printk(KERN_WARNING, ha, "Unable to allocate " "(%d KB) for FCE.\n", FCE_SIZE / 1024); - goto cont_alloc; + goto try_eft; } memset(tc, 0, FCE_SIZE); @@ -803,7 +796,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, tc_dma); ha->flags.fce_enabled = 0; - goto cont_alloc; + goto try_eft; } qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n", @@ -813,6 +806,32 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) ha->flags.fce_enabled = 1; ha->fce_dma = tc_dma; ha->fce = tc; +try_eft: + /* Allocate memory for Extended Trace Buffer. */ + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, + GFP_KERNEL); + if (!tc) { + qla_printk(KERN_WARNING, ha, "Unable to allocate " + "(%d KB) for EFT.\n", EFT_SIZE / 1024); + goto cont_alloc; + } + + memset(tc, 0, EFT_SIZE); + rval = qla2x00_enable_eft_trace(ha, tc_dma, EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, "Unable to initialize " + "EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, + tc_dma); + goto cont_alloc; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", + EFT_SIZE / 1024); + + eft_size = EFT_SIZE; + ha->eft_dma = tc_dma; + ha->eft = tc; } cont_alloc: req_q_size = ha->request_q_length * sizeof(request_t); @@ -1242,10 +1261,10 @@ static int qla2x00_fw_ready(scsi_qla_host_t *ha) { int rval; - unsigned long wtime, mtime; + unsigned long wtime, mtime, cs84xx_time; uint16_t min_wait; /* Minimum wait time if loop is down */ uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t fw_state; + uint16_t state[3]; rval = QLA_SUCCESS; @@ -1274,12 +1293,34 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) ha->host_no)); do { - rval = qla2x00_get_firmware_state(ha, &fw_state); + rval = qla2x00_get_firmware_state(ha, state); if (rval == QLA_SUCCESS) { - if (fw_state < FSTATE_LOSS_OF_SYNC) { + if (state[0] < FSTATE_LOSS_OF_SYNC) { ha->device_flags &= ~DFLG_NO_CABLE; } - if (fw_state == FSTATE_READY) { + if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) { + DEBUG16(printk("scsi(%ld): fw_state=%x " + "84xx=%x.\n", ha->host_no, state[0], + state[2])); + if ((state[2] & FSTATE_LOGGED_IN) && + (state[2] & FSTATE_WAITING_FOR_VERIFY)) { + DEBUG16(printk("scsi(%ld): Sending " + "verify iocb.\n", ha->host_no)); + + cs84xx_time = jiffies; + rval = qla84xx_init_chip(ha); + if (rval != QLA_SUCCESS) + break; + + /* Add time taken to initialize. */ + cs84xx_time = jiffies - cs84xx_time; + wtime += cs84xx_time; + mtime += cs84xx_time; + DEBUG16(printk("scsi(%ld): Increasing " + "wait time by %ld. New time %ld\n", + ha->host_no, cs84xx_time, wtime)); + } + } else if (state[0] == FSTATE_READY) { DEBUG(printk("scsi(%ld): F/W Ready - OK \n", ha->host_no)); @@ -1293,7 +1334,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - fw_state != FSTATE_READY) { + state[0] != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ @@ -1318,11 +1359,11 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) msleep(500); DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); } while (1); DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n", - ha->host_no, fw_state, jiffies)); + ha->host_no, state[0], jiffies)); if (rval) { DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n", @@ -1467,18 +1508,25 @@ qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *de index = (ha->pdev->subsystem_device & 0xff); if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && index < QLA_MODEL_NAMES) - ha->model_desc = qla2x00_model_name[index * 2 + 1]; + 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 && index < QLA_MODEL_NAMES) { strcpy(ha->model_number, qla2x00_model_name[index * 2]); - ha->model_desc = qla2x00_model_name[index * 2 + 1]; + strncpy(ha->model_desc, + qla2x00_model_name[index * 2 + 1], + sizeof(ha->model_desc) - 1); } else { strcpy(ha->model_number, def); } } + if (IS_FWI2_CAPABLE(ha)) + qla2xxx_get_vpd_field(ha, "\x82", ha->model_desc, + sizeof(ha->model_desc)); } /* On sparc systems, obtain port and node WWN from firmware @@ -1830,12 +1878,11 @@ qla2x00_rport_del(void *data) { fc_port_t *fcport = data; struct fc_rport *rport; - unsigned long flags; - spin_lock_irqsave(&fcport->rport_lock, flags); + spin_lock_irq(fcport->ha->host->host_lock); rport = fcport->drport; fcport->drport = NULL; - spin_unlock_irqrestore(&fcport->rport_lock, flags); + spin_unlock_irq(fcport->ha->host->host_lock); if (rport) fc_remote_port_delete(rport); } @@ -1864,7 +1911,6 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) atomic_set(&fcport->state, FCS_UNCONFIGURED); fcport->flags = FCF_RLC_SUPPORT; fcport->supported_classes = FC_COS_UNSPECIFIED; - spin_lock_init(&fcport->rport_lock); return fcport; } @@ -1973,8 +2019,10 @@ qla2x00_configure_loop(scsi_qla_host_t *ha) if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - if (test_bit(RSCN_UPDATE, &save_flags)) + if (test_bit(RSCN_UPDATE, &save_flags)) { + ha->flags.rscn_queue_overflow = 1; set_bit(RSCN_UPDATE, &ha->dpc_flags); + } } return (rval); @@ -2209,28 +2257,24 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) { struct fc_rport_identifiers rport_ids; struct fc_rport *rport; - unsigned long flags; if (fcport->drport) qla2x00_rport_del(fcport); - if (fcport->rport) - return; rport_ids.node_name = wwn_to_u64(fcport->node_name); rport_ids.port_name = wwn_to_u64(fcport->port_name); rport_ids.port_id = fcport->d_id.b.domain << 16 | fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - rport = fc_remote_port_add(ha->host, 0, &rport_ids); + fcport->rport = rport = fc_remote_port_add(ha->host, 0, &rport_ids); if (!rport) { qla_printk(KERN_WARNING, ha, "Unable to allocate fc remote port!\n"); return; } - spin_lock_irqsave(&fcport->rport_lock, flags); - fcport->rport = rport; + spin_lock_irq(fcport->ha->host->host_lock); *((fc_port_t **)rport->dd_data) = fcport; - spin_unlock_irqrestore(&fcport->rport_lock, flags); + spin_unlock_irq(fcport->ha->host->host_lock); rport->supported_classes = fcport->supported_classes; @@ -2419,7 +2463,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) if (fcport->loop_id == FC_NO_LOOP_ID) { fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id( + to_qla_parent(ha), fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -2444,7 +2489,8 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) /* Find a new loop ID to use. */ fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(ha, fcport); + rval = qla2x00_find_new_loop_id(to_qla_parent(ha), + fcport); if (rval != QLA_SUCCESS) { /* Ran out of IDs to use */ break; @@ -2529,7 +2575,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) { kfree(swl); swl = NULL; - } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) { + } else if (ql2xiidmaenable && + qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) { qla2x00_gpsc(ha, swl); } } @@ -3207,6 +3254,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) if (ha->flags.online) { ha->flags.online = 0; clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags); + ha->qla_stats.total_isp_aborts++; qla_printk(KERN_INFO, ha, "Performing ISP error recovery - ha= %p.\n", ha); @@ -3247,17 +3295,6 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt = 0; clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags); - if (ha->eft) { - memset(ha->eft, 0, EFT_SIZE); - rval = qla2x00_enable_eft_trace(ha, - ha->eft_dma, EFT_NUM_BUFFERS); - if (rval) { - qla_printk(KERN_WARNING, ha, - "Unable to reinitialize EFT " - "(%d).\n", rval); - } - } - if (ha->fce) { ha->flags.fce_enabled = 1; memset(ha->fce, 0, @@ -3272,6 +3309,17 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->flags.fce_enabled = 0; } } + + if (ha->eft) { + memset(ha->eft, 0, EFT_SIZE); + rval = qla2x00_enable_eft_trace(ha, + ha->eft_dma, EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, + "Unable to reinitialize EFT " + "(%d).\n", rval); + } + } } else { /* failed the ISP abort */ ha->flags.online = 1; if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) { @@ -3609,7 +3657,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) 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 = cpu_to_le16(nv->login_timeout); + icb->login_timeout = nv->login_timeout; /* Set minimum RATOV to 100 tenths of a second. */ ha->r_a_tov = 100; @@ -4010,7 +4058,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) if (!ha->parent) return -EINVAL; - rval = qla2x00_fw_ready(ha); + rval = qla2x00_fw_ready(ha->parent); if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); @@ -4019,7 +4067,7 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) ha->flags.management_server_logged_in = 0; /* Login to SNS first */ - qla24xx_login_fabric(ha, NPH_SNS, 0xff, 0xff, 0xfc, + qla24xx_login_fabric(ha->parent, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1); if (mb[0] != MBS_COMMAND_COMPLETE) { DEBUG15(qla_printk(KERN_INFO, ha, @@ -4033,7 +4081,77 @@ qla24xx_configure_vhba(scsi_qla_host_t *ha) atomic_set(&ha->loop_state, LOOP_UP); set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - rval = qla2x00_loop_resync(ha); + rval = qla2x00_loop_resync(ha->parent); return rval; } + +/* 84XX Support **************************************************************/ + +static LIST_HEAD(qla_cs84xx_list); +static DEFINE_MUTEX(qla_cs84xx_mutex); + +static struct qla_chip_state_84xx * +qla84xx_get_chip(struct scsi_qla_host *ha) +{ + struct qla_chip_state_84xx *cs84xx; + + mutex_lock(&qla_cs84xx_mutex); + + /* Find any shared 84xx chip. */ + list_for_each_entry(cs84xx, &qla_cs84xx_list, list) { + if (cs84xx->bus == ha->pdev->bus) { + kref_get(&cs84xx->kref); + goto done; + } + } + + cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL); + if (!cs84xx) + goto done; + + kref_init(&cs84xx->kref); + spin_lock_init(&cs84xx->access_lock); + mutex_init(&cs84xx->fw_update_mutex); + cs84xx->bus = ha->pdev->bus; + + list_add_tail(&cs84xx->list, &qla_cs84xx_list); +done: + mutex_unlock(&qla_cs84xx_mutex); + return cs84xx; +} + +static void +__qla84xx_chip_release(struct kref *kref) +{ + struct qla_chip_state_84xx *cs84xx = + container_of(kref, struct qla_chip_state_84xx, kref); + + mutex_lock(&qla_cs84xx_mutex); + list_del(&cs84xx->list); + mutex_unlock(&qla_cs84xx_mutex); + kfree(cs84xx); +} + +void +qla84xx_put_chip(struct scsi_qla_host *ha) +{ + if (ha->cs84xx) + kref_put(&ha->cs84xx->kref, __qla84xx_chip_release); +} + +static int +qla84xx_init_chip(scsi_qla_host_t *ha) +{ + int rval; + uint16_t status[2]; + + mutex_lock(&ha->cs84xx->fw_update_mutex); + + rval = qla84xx_verify_chip(ha, status); + + mutex_unlock(&ha->cs84xx->fw_update_mutex); + + return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: + QLA_SUCCESS; +}