📄 qla_init.c
字号:
sizeof(nv->model_number)) != 0) { char *st, *en; strncpy(ha->model_number, nv->model_number, sizeof(nv->model_number)); st = en = ha->model_number; en += sizeof(nv->model_number) - 1; while (en > st) { if (*en != 0x20 && *en != 0x00) break; *en-- = '\0'; } } else { uint16_t index; index = (ha->pdev->subsystem_device & 0xff); if (index < QLA_MODEL_NAMES) { strcpy(ha->model_number, qla2x00_model_name[index]); ha->model_desc = qla2x00_model_desc[index]; } else { strcpy(ha->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++; /* 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. */ 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->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) { 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_add(void *data){ fc_port_t *fcport = data; qla2x00_reg_remote_port(fcport->ha, fcport);}static voidqla2x00_rport_del(void *data){ fc_port_t *fcport = data; if (fcport->rport) fc_remote_port_delete(fcport->rport); fcport->rport = NULL;}/** * 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. */fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags){ fc_port_t *fcport; fcport = kmalloc(sizeof(fc_port_t), flags); if (fcport == NULL) return (fcport); /* Setup fcport template structure. */ memset(fcport, 0, sizeof (fc_port_t)); fcport->ha = ha; fcport->port_type = FCT_UNKNOWN; fcport->loop_id = FC_NO_LOOP_ID; fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; atomic_set(&fcport->state, FCS_UNCONFIGURED); fcport->flags = FCF_RLC_SUPPORT; fcport->supported_classes = FC_COS_UNSPECIFIED; INIT_WORK(&fcport->rport_add_work, qla2x00_rport_add, fcport); INIT_WORK(&fcport->rport_del_work, qla2x00_rport_del, fcport); 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->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; 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, &ha->fcports, list) { if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->port_type != FCT_BROADCAST && (fcport->flags & FCF_FABRIC_DEVICE) == 0) { DEBUG(printk("scsi(%ld): Marking port lost, " "loop_id=0x%04x\n", ha->host_no, fcport->loop_id)); atomic_set(&fcport->state, FCS_DEVICE_LOST); fcport->flags &= ~FCF_FARP_DONE; } } /* Add devices to port list. */ id_iter = (char *)ha->gid_list; for (index = 0; index < entries; index++) { domain = ((struct gid_list_info *)id_iter)->domain; area = ((struct gid_list_info *)id_iter)->area; al_pa = ((struct gid_list_info *)id_iter)->al_pa; if (IS_QLA2100(ha) || IS_QLA2200(ha)) loop_id = (uint16_t) ((struct gid_list_info *)id_iter)->loop_id_2100; else loop_id = le16_to_cpu( ((struct gid_list_info *)id_iter)->loop_id); id_iter += ha->gid_list_info_size; /* Bypass reserved domain fields. */ if ((domain & 0xf0) == 0xf0) continue; /* Bypass if not same domain and area of adapter. */ if (area && domain && (area != ha->d_id.b.area || domain != ha->d_id.b.domain)) continue; /* Bypass invalid local loop ID. */ if (loop_id > LAST_LOCAL_LOOP_ID) continue; /* Fill in member data. */ new_fcport->d_id.b.domain = domain; new_fcport->d_id.b.area = area; new_fcport->d_id.b.al_pa = al_pa; new_fcport->loop_id = loop_id; rval2 = qla2x00_get_port_database(ha, new_fcport, 0); if (rval2 != QLA_SUCCESS) { DEBUG2(printk("scsi(%ld): Failed to retrieve fcport " "information -- get_port_database=%x, " "loop_id=0x%04x\n", ha->host_no, rval2, new_fcport->loop_id)); continue; } /* Check for matching device in port list. */ found = 0; fcport = NULL; list_for_each_entry(fcport, &ha->fcports, list) { if (memcmp(new_fcport->port_name, fcport->port_name, WWN_SIZE)) continue; fcport->flags &= ~(FCF_FABRIC_DEVICE | FCF_PERSISTENT_BOUND); fcport->loop_id = new_fcport->loop_id; fcport->port_type = new_fcport->port_type; fcport->d_id.b24 = new_fcport->d_id.b24; memcpy(fcport->node_name, new_fcport->node_name, WWN_SIZE); found++; break; } if (!found) { /* New device, add to fcports list. */ new_fcport->flags &= ~FCF_PERSISTENT_BOUND; list_add_tail(&new_fcport->list, &ha->fcports); /* Allocate a new replacement fcport. */ fcport = new_fcport; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -