qla_init.c
来自「linux 内核源代码」· C语言 代码 · 共 2,472 行 · 第 1/5 页
C
2,472 行
chksum += *ptr++; DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->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 < 1) { /* Reset NVRAM data. */ qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], 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->parameter_block_version = ICB_VERSION; if (IS_QLA23XX(ha)) { nv->firmware_options[0] = BIT_2 | BIT_1; nv->firmware_options[1] = BIT_7 | BIT_5; nv->add_firmware_options[0] = BIT_5; nv->add_firmware_options[1] = BIT_5 | BIT_4; nv->frame_payload_size = __constant_cpu_to_le16(2048); nv->special_options[1] = BIT_7; } else if (IS_QLA2200(ha)) { nv->firmware_options[0] = BIT_2 | BIT_1; nv->firmware_options[1] = BIT_7 | BIT_5; nv->add_firmware_options[0] = BIT_5; nv->add_firmware_options[1] = BIT_5 | BIT_4; nv->frame_payload_size = __constant_cpu_to_le16(1024); } else if (IS_QLA2100(ha)) { nv->firmware_options[0] = BIT_3 | BIT_1; nv->firmware_options[1] = BIT_5; nv->frame_payload_size = __constant_cpu_to_le16(1024); } nv->max_iocb_allocation = __constant_cpu_to_le16(256); nv->execution_throttle = __constant_cpu_to_le16(16); nv->retry_count = 8; nv->retry_delay = 1; nv->port_name[0] = 33; nv->port_name[3] = 224; nv->port_name[4] = 139; qla2xxx_nvram_wwn_from_ofw(ha, nv); nv->login_timeout = 4; /* * Set default host adapter parameters */ nv->host_p[1] = BIT_2; nv->reset_delay = 5; nv->port_down_retry_count = 8; nv->max_luns_per_target = __constant_cpu_to_le16(8); nv->link_down_timeout = 60; rval = 1; }#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) /* * The SN2 does not provide BIOS emulation which means you can't change * potentially bogus BIOS settings. Force the use of default settings * for link rate and frame size. Hope that the rest of the settings * are valid. */ if (ia64_platform_is("sn2")) { nv->frame_payload_size = __constant_cpu_to_le16(2048); if (IS_QLA23XX(ha)) nv->special_options[1] = BIT_7; }#endif /* Reset Initialization control block */ memset(icb, 0, ha->init_cb_size); /* * Setup driver NVRAM options. */ nv->firmware_options[0] |= (BIT_6 | BIT_1); nv->firmware_options[0] &= ~(BIT_5 | BIT_4); nv->firmware_options[1] |= (BIT_5 | BIT_0); nv->firmware_options[1] &= ~BIT_4; if (IS_QLA23XX(ha)) { nv->firmware_options[0] |= BIT_2; nv->firmware_options[0] &= ~BIT_3; nv->add_firmware_options[1] |= BIT_5 | BIT_4; if (IS_QLA2300(ha)) { if (ha->fb_rev == FPM_2310) { strcpy(ha->model_number, "QLA2310"); } else { strcpy(ha->model_number, "QLA2300"); } } else { qla2x00_set_model_info(ha, nv->model_number, sizeof(nv->model_number), "QLA23xx"); } } else if (IS_QLA2200(ha)) { nv->firmware_options[0] |= BIT_2; /* * 'Point-to-point preferred, else loop' is not a safe * connection mode setting. */ if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) == (BIT_5 | BIT_4)) { /* Force 'loop preferred, else point-to-point'. */ nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4); nv->add_firmware_options[0] |= BIT_5; } strcpy(ha->model_number, "QLA22xx"); } else /*if (IS_QLA2100(ha))*/ { strcpy(ha->model_number, "QLA2100"); } /* * Copy over NVRAM RISC parameter block to initialization control block. */ dptr1 = (uint8_t *)icb; dptr2 = (uint8_t *)&nv->parameter_block_version; cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version; while (cnt--) *dptr1++ = *dptr2++; /* Copy 2nd half. */ dptr1 = (uint8_t *)icb->add_firmware_options; cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options; while (cnt--) *dptr1++ = *dptr2++; /* Use alternate WWN? */ if (nv->host_p[1] & BIT_7) { 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] & BIT_6) == 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. */ if (nv->host_p[0] & BIT_7) ql2xextended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) ha->flags.disable_risc_code_load = 0; ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; ha->flags.disable_serdes = 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; memcpy(ha->fw_seriallink_options, nv->seriallink_options, sizeof(ha->fw_seriallink_options)); /* save HBA serial number */ ha->serial0 = icb->port_name[5]; ha->serial1 = icb->port_name[6]; ha->serial2 = icb->port_name[7]; ha->node_name = icb->node_name; ha->port_name = icb->port_name; icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); ha->retry_count = nv->retry_count; /* Set minimum login_timeout to 4 seconds. */ if (nv->login_timeout < ql2xlogintimeout) nv->login_timeout = ql2xlogintimeout; if (nv->login_timeout < 4) nv->login_timeout = 4; ha->login_timeout = nv->login_timeout; icb->login_timeout = nv->login_timeout; /* Set minimum RATOV to 200 tenths of a second. */ ha->r_a_tov = 200; 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 (nv->link_down_timeout == 0) { ha->loop_down_abort_time = (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); } else { ha->link_down_timeout = 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 = 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 = nv->retry_count; if (ha->port_down_retry_count == 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; icb->lun_enables = __constant_cpu_to_le16(0); icb->command_resource_count = 0; icb->immediate_notify_resource_count = 0; icb->timeout = __constant_cpu_to_le16(0); if (IS_QLA2100(ha) || IS_QLA2200(ha)) { /* Enable RIO */ icb->firmware_options[0] &= ~BIT_3; icb->add_firmware_options[0] &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); icb->add_firmware_options[0] |= BIT_2; icb->response_accumulation_timer = 3; icb->interrupt_delay_timer = 5; ha->flags.process_response_queue = 1; } else { /* Enable ZIO. */ if (!ha->flags.init_done) { ha->zio_mode = icb->add_firmware_options[0] & (BIT_3 | BIT_2 | BIT_1 | BIT_0); ha->zio_timer = icb->interrupt_delay_timer ? icb->interrupt_delay_timer: 2; } icb->add_firmware_options[0] &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); ha->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", ha->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->add_firmware_options[0] |= (uint8_t)ha->zio_mode; icb->interrupt_delay_timer = (uint8_t)ha->zio_timer; ha->flags.process_response_queue = 1; } } if (rval) { DEBUG2_3(printk(KERN_WARNING "scsi(%ld): NVRAM configuration failed!\n", ha->host_no)); } return (rval);}static voidqla2x00_rport_del(void *data){ fc_port_t *fcport = data; struct fc_rport *rport; unsigned long flags; spin_lock_irqsave(&fcport->rport_lock, flags); rport = fcport->drport; fcport->drport = NULL; spin_unlock_irqrestore(&fcport->rport_lock, flags); if (rport) fc_remote_port_delete(rport);}/** * qla2x00_alloc_fcport() - Allocate a generic fcport. * @ha: HA context * @flags: allocation flags * * Returns a pointer to the allocated fcport, or NULL, if none available. */static fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags){ fc_port_t *fcport; fcport = kzalloc(sizeof(fc_port_t), flags); if (!fcport) return NULL; /* Setup fcport template structure. */ fcport->ha = ha; fcport->vp_idx = ha->vp_idx; 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; spin_lock_init(&fcport->rport_lock); return fcport;}/* * qla2x00_configure_loop * Updates Fibre Channel Device Database with what is actually on loop. * * Input: * ha = adapter block pointer. * * Returns: * 0 = success. * 1 = error. * 2 = database was full and device was not configured. */static intqla2x00_configure_loop(scsi_qla_host_t *ha){ int rval; unsigned long flags, save_flags; rval = QLA_SUCCESS; /* Get Initiator ID */ if (test_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags)) { rval = qla2x00_configure_hba(ha); if (rval != QLA_SUCCESS) { DEBUG(printk("scsi(%ld): Unable to configure HBA.\n", ha->host_no)); return (rval); } } save_flags = flags = ha->dpc_flags; DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n", ha->host_no, flags)); /* * If we have both an RSCN and PORT UPDATE pending then handle them * both at the same time. */ clear_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); clear_bit(RSCN_UPDATE, &ha->dpc_flags); /* Determine what we need to do */ if (ha->current_topology == ISP_CFG_FL && (test_bit(LOCAL_LOOP_UPDATE, &flags))) { ha->flags.rscn_queue_overflow = 1; set_bit(RSCN_UPDATE, &flags); } else if (ha->current_topology == ISP_CFG_F && (test_bit(LOCAL_LOOP_UPDATE, &flags))) { ha->flags.rscn_queue_overflow = 1; set_bit(RSCN_UPDATE, &flags); clear_bit(LOCAL_LOOP_UPDATE, &flags); } else if (ha->current_topology == ISP_CFG_N) { clear_bit(RSCN_UPDATE, &flags); } else if (!ha->flags.online || (test_bit(ABORT_ISP_ACTIVE, &flags))) { ha->flags.rscn_queue_overflow = 1; set_bit(RSCN_UPDATE, &flags); set_bit(LOCAL_LOOP_UPDATE, &flags); } if (test_bit(LOCAL_LOOP_UPDATE, &flags)) { if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { rval = QLA_FUNCTION_FAILED; } else { rval = qla2x00_configure_local_loop(ha); } } if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) { if (LOOP_TRANSITION(ha)) { rval = QLA_FUNCTION_FAILED; } else { rval = qla2x00_configure_fabric(ha); } } if (rval == QLA_SUCCESS) { if (atomic_read(&ha->loop_down_timer) || test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) { rval = QLA_FUNCTION_FAILED; } else { atomic_set(&ha->loop_state, LOOP_READY); DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no)); } } if (rval) { DEBUG2_3(printk("%s(%ld): *** FAILED ***\n", __func__, ha->host_no)); } else { DEBUG3(printk("%s: exiting normally\n", __func__)); } /* Restore state if a resync event occured during processing */ 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)) set_bit(RSCN_UPDATE, &ha->dpc_flags); } return (rval);}/* * qla2x00_configure_local_loop * Updates Fibre Channel Device Database with local loop devices. * * Input: * ha = adapter block pointer. * * Returns: * 0 = success. */static intqla2x00_configure_local_loop(scsi_qla_host_t *ha){ int rval, rval2; int found_devs; int found; fc_port_t *fcport, *new_fcport; uint16_t index; uint16_t entries; char *id_iter; uint16_t loop_id; uint8_t domain, area, al_pa; scsi_qla_host_t *pha = to_qla_parent(ha); found_devs = 0; new_fcport = NULL; entries = MAX_FIBRE_DEVICES; DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", ha->host_no)); DEBUG3(qla2x00_get_fcal_position_map(ha, NULL)); /* Get list of logged in devices. */ memset(ha->gid_list, 0, GID_LIST_SIZE); rval = qla2x00_get_id_list(ha, ha->gid_list, ha->gid_list_dma, &entries); if (rval != QLA_SUCCESS) goto cleanup_allocation; DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n", ha->host_no, entries)); DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list, entries * sizeof(struct gid_list_info))); /* Allocate temporary fcport for any new fcports discovered. */ new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL); if (new_fcport == NULL) { rval = QLA_MEMORY_ALLOC_FAILED; goto cleanup_allocation; } new_fcport->flags &= ~FCF_FABRIC_DEVICE; /* * Mark local devices that were present with FCF_DEVICE_LOST for now. */ list_for_each_entry(fcport, &pha->fcports, list) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?