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 + -
显示快捷键?