qla_init.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,528 行 · 第 1/5 页

C
2,528
字号
 *      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);	ha->mem_err = 0 ;	/* 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 (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {			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 {			qla2x00_config_os(ha);			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;	struct dev_id {		uint8_t	al_pa;		uint8_t	area;		uint8_t	domain;				uint8_t	loop_id_2100;	/* ISP2100/ISP2200 -- 4 bytes. */		uint16_t loop_id;	/* ISP23XX         -- 6 bytes. */	} *id_list;#define MAX_ID_LIST_SIZE (sizeof(struct dev_id) * MAX_FIBRE_DEVICES)	dma_addr_t	id_list_dma;	char		*id_iter;	uint16_t	loop_id;	uint8_t		domain, area, al_pa;	found_devs = 0;	new_fcport = NULL;	entries = MAX_FIBRE_DEVICES;	id_list = pci_alloc_consistent(ha->pdev, MAX_ID_LIST_SIZE,	    &id_list_dma);	if (id_list == NULL) {		DEBUG2(printk("scsi(%ld): Failed to allocate memory, No local "		    "loop\n", ha->host_no));		qla_printk(KERN_WARNING, ha,		    "Memory Allocation failed - port_list");		ha->mem_err++;		return (QLA_MEMORY_ALLOC_FAILED);	}	memset(id_list, 0, MAX_ID_LIST_SIZE);	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. */	rval = qla2x00_get_id_list(ha, id_list, id_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 *)id_list,	    entries * sizeof(struct dev_id)));	/* 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 *)id_list;	for (index = 0; index < entries; index++) {		domain = ((struct dev_id *)id_iter)->domain;		area = ((struct dev_id *)id_iter)->area;		al_pa = ((struct dev_id *)id_iter)->al_pa;		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {			loop_id =			    (uint16_t)((struct dev_id *)id_iter)->loop_id_2100;			id_iter += 4;		} else {			loop_id =			    le16_to_cpu(((struct dev_id *)id_iter)->loop_id);			id_iter += 6;		}		/* Bypass reserved domain fields. */		if ((domain & 0xf0) == 0xf0)			continue;		/* Bypass if not same domain and area of adapter. */		if (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;		}		qla2x00_update_fcport(ha, fcport);		found_devs++;	}cleanup_allocation:	pci_free_consistent(ha->pdev, MAX_ID_LIST_SIZE, id_list, id_list_dma);	if (new_fcport)		kfree(new_fcport);	if (rval != QLA_SUCCESS) {		DEBUG2(printk("scsi(%ld): Configure local loop error exit: "		    "rval=%x\n", ha->host_no, rval));	}	if (found_devs) {		ha->device_flags |= DFLG_LOCAL_DEVICES;		ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES;	}	return (rval);}static voidqla2x00_probe_for_all_luns(scsi_qla_host_t *ha) {	fc_port_t	*fcport;	qla2x00_mark_all_devices_lost(ha);  	list_for_each_entry(fcport, &ha->fcports, list) {		if (fcport->port_type != FCT_TARGET)			continue;		qla2x00_update_fcport(ha, fcport); 	}}/* * qla2x00_update_fcport *	Updates device on list. * * Input: *	ha = adapter block pointer. *	fcport = port structure pointer. * * Return: *	0  - Success *  BIT_0 - error * * Context: *	Kernel context. */static voidqla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport){	uint16_t	index;	unsigned long flags;	srb_t *sp;	fcport->ha = ha;	fcport->login_retry = 0;	fcport->port_login_retry_count = ha->port_down_retry_count *	    PORT_RETRY_TIME;	atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *	    PORT_RETRY_TIME);	fcport->flags &= ~FCF_LOGIN_NEEDED;	/*	 * Check for outstanding cmd on tape Bypass LUN discovery if active	 * command on tape.	 */	if (fcport->flags & FCF_TAPE_PRESENT) {		spin_lock_irqsave(&ha->hardware_lock, flags);		for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {			if ((sp = ha->outstanding_cmds[index]) != 0) {				if (sp->fclun->fcport == fcport) {					atomic_set(&fcport->state, FCS_ONLINE);					spin_unlock_irqrestore(					    &ha->hardware_lock, flags);					return;				}			}		}		spin_unlock_irqrestore(&ha->hardware_lock, flags);	}	/* Do LUN discovery. */	if (fcport->port_type == FCT_INITIATOR ||	    fcport->port_type == FCT_BROADCAST) {		fcport->device_type = TYPE_PROCESSOR;	} else {		qla2x00_lun_discovery(ha, fcport);	}	atomic_set(&fcport->state, FCS_ONLINE);}/* * qla2x00_lun_discovery *	Issue SCSI inquiry command for LUN discovery. * * Input: *	ha:		adapter state pointer. *	fcport:		FC port structure pointer. * * Context: *	Kernel context. */static voidqla2x00_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport){	inq_cmd_rsp_t	*inq;	dma_addr_t	inq_dma;	uint16_t	lun;	inq = pci_alloc_consistent(ha->pdev, sizeof(inq_cmd_rsp_t), &inq_dma);	if (inq == NULL) {		qla_printk(KERN_WARNING, ha,		    "Memory Allocation failed - INQ\n");		return;	}	/* If report LUN works, exit. */	if (qla2x00_rpt_lun_discovery(ha, fcport, inq, inq_dma) !=	    QLA_SUCCESS) {		for (lun = 0; lun < ha->max_probe_luns; lun++) {			/* Configure LUN. */			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);		}	}	pci_free_consistent(ha->pdev, sizeof(inq_cmd_rsp_t), inq, inq_dma);}/* * qla2x00_rpt_lun_discovery *	Issue SCSI report LUN command for LUN discovery. * * Input: *	ha:		adapter state pointer. *	fcport:		FC port structure pointer. * * Returns: *	qla2x00 local function return status code. * * Context: *	Kernel context. */static intqla2x00_rpt_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport,    inq_cmd_rsp_t *inq, dma_addr_t inq_dma){	int			rval;	uint32_t		len, cnt;	uint16_t		lun;	rpt_lun_cmd_rsp_t	*rlc;	dma_addr_t		rlc_dma;	/* Assume a failed status */	rval = QLA_FUNCTION_FAILED;	/* No point in continuing if the device doesn't support RLC */	if ((fcport->flags & FCF_RLC_SUPPORT) == 0)		return (rval);	rlc = pci_alloc_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t),	    &rlc_dma);	if (rlc == NULL) {		qla_printk(KERN_WARNING, ha,			"Memory Allocation failed - RLC");		return QLA_MEMORY_ALLOC_FAILED;	}	rval = qla2x00_report_lun(ha, fcport, rlc, rlc_dma);	if (rval != QLA_SUCCESS) {		pci_free_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), rlc,		    rlc_dma);		return (rval);	}	/* Always add a fc_lun_t structure for lun 0 -- mid-layer requirement */	qla2x00_add_lun(fcport, 0);	/* Configure LUN list. */	len = be32_to_cpu(rlc->list.hdr.len);	len /= 8;	for (cnt = 0; cnt < len; cnt++) {		lun = CHAR_TO_SHORT(rlc->list.lst[cnt].lsb,		    rlc->list.lst[cnt].msb.b);		DEBUG3(printk("scsi(%ld): RLC lun = (%d)\n", ha->host_no, lun));		/* We only support 0 through MAX_LUNS-1 range */		if (lun < MAX_LUNS) {			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);		}	}	atomic_set(&fcport->state, FCS_ONLINE);	pci_free_consistent(ha->pdev, sizeof(rpt_lun_cmd_rsp_t), rlc, rlc_dma);	return (rval);}/* * qla2x00_report_lun *	Issue SCSI report LUN command. * * Input: *	ha:		adapter state pointer. *	fcport:		FC port structure pointer. *	mem:		pointer to dma memory object for report LUN IOCB *			packet. * * Returns: *	qla2x00 local function return status code. * * Context: *	Kernel context. */static intqla2x00_report_lun(scsi_qla_host_t *ha,    fc_port_t *fcport, rpt_lun_cmd_rsp_t *rlc, dma_addr_t rlc_dma){	int rval;	uint16_t retries;	uint16_t comp_status;	uint16_t scsi_status;	rval = QLA_FUNCTION_FAILED;	for (retries = 3; retries; retries--) {		memset(rlc, 0, sizeof(rpt_lun_cmd_rsp_t));		rlc->p.cmd.entry_type = COMMAND_A64_TYPE;		rlc->p.cmd.entry_count = 1;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?