⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mptsas.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		break;	}	/*	 * Set Min programmed link rate.	 */	switch (phy_info->programmed_link_rate &			MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {	case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:		phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;		break;	case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:		phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;		break;	default:		break;	}	if (!phy_info->phy) {		error = sas_phy_add(phy);		if (error) {			sas_phy_free(phy);			goto out;		}		phy_info->phy = phy;	}	if (!phy_info->attached.handle ||			!phy_info->port_details)		goto out;	port = mptsas_get_port(phy_info);	ioc = phy_to_ioc(phy_info->phy);	if (phy_info->sas_port_add_phy) {		if (!port) {			port = sas_port_alloc_num(dev);			if (!port) {				error = -ENOMEM;				goto out;			}			error = sas_port_add(port);			if (error) {				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT					"%s: exit at line=%d\n", ioc->name,					__FUNCTION__, __LINE__));				goto out;			}			mptsas_set_port(ioc, phy_info, port);			dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT			    "sas_port_alloc: port=%p dev=%p port_id=%d\n",			    ioc->name, port, dev, port->port_identifier));		}		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_port_add_phy: phy_id=%d\n",		    ioc->name, phy_info->phy_id));		sas_port_add_phy(port, phy_info->phy);		phy_info->sas_port_add_phy = 0;	}	if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {		struct sas_rphy *rphy;		struct device *parent;		struct sas_identify identify;		parent = dev->parent->parent;		/*		 * Let the hotplug_work thread handle processing		 * the adding/removing of devices that occur		 * after start of day.		 */		if (ioc->sas_discovery_runtime &&			mptsas_is_end_device(&phy_info->attached))				goto out;		mptsas_parse_device_info(&identify, &phy_info->attached);		if (scsi_is_host_device(parent)) {			struct mptsas_portinfo *port_info;			int i;			mutex_lock(&ioc->sas_topology_mutex);			port_info = mptsas_find_portinfo_by_handle(ioc,								   ioc->handle);			mutex_unlock(&ioc->sas_topology_mutex);			for (i = 0; i < port_info->num_phys; i++)				if (port_info->phy_info[i].identify.sas_address ==				    identify.sas_address) {					sas_port_mark_backlink(port);					goto out;				}		} else if (scsi_is_sas_rphy(parent)) {			struct sas_rphy *parent_rphy = dev_to_rphy(parent);			if (identify.sas_address ==			    parent_rphy->identify.sas_address) {				sas_port_mark_backlink(port);				goto out;			}		}		switch (identify.device_type) {		case SAS_END_DEVICE:			rphy = sas_end_device_alloc(port);			break;		case SAS_EDGE_EXPANDER_DEVICE:		case SAS_FANOUT_EXPANDER_DEVICE:			rphy = sas_expander_alloc(port, identify.device_type);			break;		default:			rphy = NULL;			break;		}		if (!rphy) {			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT				"%s: exit at line=%d\n", ioc->name,				__FUNCTION__, __LINE__));			goto out;		}		rphy->identify = identify;		error = sas_rphy_add(rphy);		if (error) {			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT				"%s: exit at line=%d\n", ioc->name,				__FUNCTION__, __LINE__));			sas_rphy_free(rphy);			goto out;		}		mptsas_set_rphy(ioc, phy_info, rphy);	} out:	return error;}static intmptsas_probe_hba_phys(MPT_ADAPTER *ioc){	struct mptsas_portinfo *port_info, *hba;	int error = -ENOMEM, i;	hba = kzalloc(sizeof(*port_info), GFP_KERNEL);	if (! hba)		goto out;	error = mptsas_sas_io_unit_pg0(ioc, hba);	if (error)		goto out_free_port_info;	mptsas_sas_io_unit_pg1(ioc);	mutex_lock(&ioc->sas_topology_mutex);	ioc->handle = hba->phy_info[0].handle;	port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);	if (!port_info) {		port_info = hba;		list_add_tail(&port_info->list, &ioc->sas_topology);	} else {		for (i = 0; i < hba->num_phys; i++) {			port_info->phy_info[i].negotiated_link_rate =				hba->phy_info[i].negotiated_link_rate;			port_info->phy_info[i].handle =				hba->phy_info[i].handle;			port_info->phy_info[i].port_id =				hba->phy_info[i].port_id;		}		kfree(hba->phy_info);		kfree(hba);		hba = NULL;	}	mutex_unlock(&ioc->sas_topology_mutex);	for (i = 0; i < port_info->num_phys; i++) {		mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],			(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<			 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);		mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,			(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<			 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),			 port_info->phy_info[i].handle);		port_info->phy_info[i].identify.phy_id =		    port_info->phy_info[i].phy_id = i;		if (port_info->phy_info[i].attached.handle)			mptsas_sas_device_pg0(ioc,				&port_info->phy_info[i].attached,				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),				port_info->phy_info[i].attached.handle);	}	mptsas_setup_wide_ports(ioc, port_info);	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)		mptsas_probe_one_phy(&ioc->sh->shost_gendev,		    &port_info->phy_info[i], ioc->sas_index, 1);	return 0; out_free_port_info:	kfree(hba); out:	return error;}static intmptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle){	struct mptsas_portinfo *port_info, *p, *ex;	struct device *parent;	struct sas_rphy *rphy;	int error = -ENOMEM, i, j;	ex = kzalloc(sizeof(*port_info), GFP_KERNEL);	if (!ex)		goto out;	error = mptsas_sas_expander_pg0(ioc, ex,	    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<	     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle);	if (error)		goto out_free_port_info;	*handle = ex->phy_info[0].handle;	mutex_lock(&ioc->sas_topology_mutex);	port_info = mptsas_find_portinfo_by_handle(ioc, *handle);	if (!port_info) {		port_info = ex;		list_add_tail(&port_info->list, &ioc->sas_topology);	} else {		for (i = 0; i < ex->num_phys; i++) {			port_info->phy_info[i].handle =				ex->phy_info[i].handle;			port_info->phy_info[i].port_id =				ex->phy_info[i].port_id;		}		kfree(ex->phy_info);		kfree(ex);		ex = NULL;	}	mutex_unlock(&ioc->sas_topology_mutex);	for (i = 0; i < port_info->num_phys; i++) {		mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],			(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<			 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);		if (port_info->phy_info[i].identify.handle) {			mptsas_sas_device_pg0(ioc,				&port_info->phy_info[i].identify,				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),				port_info->phy_info[i].identify.handle);			port_info->phy_info[i].identify.phy_id =			    port_info->phy_info[i].phy_id;		}		if (port_info->phy_info[i].attached.handle) {			mptsas_sas_device_pg0(ioc,				&port_info->phy_info[i].attached,				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),				port_info->phy_info[i].attached.handle);			port_info->phy_info[i].attached.phy_id =			    port_info->phy_info[i].phy_id;		}	}	parent = &ioc->sh->shost_gendev;	for (i = 0; i < port_info->num_phys; i++) {		mutex_lock(&ioc->sas_topology_mutex);		list_for_each_entry(p, &ioc->sas_topology, list) {			for (j = 0; j < p->num_phys; j++) {				if (port_info->phy_info[i].identify.handle !=						p->phy_info[j].attached.handle)					continue;				rphy = mptsas_get_rphy(&p->phy_info[j]);				parent = &rphy->dev;			}		}		mutex_unlock(&ioc->sas_topology_mutex);	}	mptsas_setup_wide_ports(ioc, port_info);	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)		mptsas_probe_one_phy(parent, &port_info->phy_info[i],		    ioc->sas_index, 0);	return 0; out_free_port_info:	if (ex) {		kfree(ex->phy_info);		kfree(ex);	} out:	return error;}/* * mptsas_delete_expander_phys * * * This will traverse topology, and remove expanders * that are no longer present */static voidmptsas_delete_expander_phys(MPT_ADAPTER *ioc){	struct mptsas_portinfo buffer;	struct mptsas_portinfo *port_info, *n, *parent;	struct mptsas_phyinfo *phy_info;	struct sas_port * port;	int i;	u64	expander_sas_address;	mutex_lock(&ioc->sas_topology_mutex);	list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {		if (port_info->phy_info &&		    (!(port_info->phy_info[0].identify.device_info &		    MPI_SAS_DEVICE_INFO_SMP_TARGET)))			continue;		if (mptsas_sas_expander_pg0(ioc, &buffer,		     (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<		     MPI_SAS_EXPAND_PGAD_FORM_SHIFT),		     port_info->phy_info[0].handle)) {			/*			 * Obtain the port_info instance to the parent port			 */			parent = mptsas_find_portinfo_by_handle(ioc,			    port_info->phy_info[0].identify.handle_parent);			if (!parent)				goto next_port;			expander_sas_address =				port_info->phy_info[0].identify.sas_address;			/*			 * Delete rphys in the parent that point			 * to this expander.  The transport layer will			 * cleanup all the children.			 */			phy_info = parent->phy_info;			for (i = 0; i < parent->num_phys; i++, phy_info++) {				port = mptsas_get_port(phy_info);				if (!port)					continue;				if (phy_info->attached.sas_address !=					expander_sas_address)					continue;				dsaswideprintk(ioc,				    dev_printk(KERN_DEBUG, &port->dev,				    MYIOC_s_FMT "delete port (%d)\n", ioc->name,				    port->port_identifier));				sas_port_delete(port);				mptsas_port_delete(ioc, phy_info->port_details);			} next_port:			phy_info = port_info->phy_info;			for (i = 0; i < port_info->num_phys; i++, phy_info++)				mptsas_port_delete(ioc, phy_info->port_details);			list_del(&port_info->list);			kfree(port_info->phy_info);			kfree(port_info);		}		/*		* Free this memory allocated from inside		* mptsas_sas_expander_pg0		*/		kfree(buffer.phy_info);	}	mutex_unlock(&ioc->sas_topology_mutex);}/* * Start of day discovery */static voidmptsas_scan_sas_topology(MPT_ADAPTER *ioc){	u32 handle = 0xFFFF;	int i;	mutex_lock(&ioc->sas_discovery_mutex);	mptsas_probe_hba_phys(ioc);	while (!mptsas_probe_expander_phys(ioc, &handle))		;	/*	  Reporting RAID volumes.	*/	if (!ioc->ir_firmware)		goto out;	if (!ioc->raid_data.pIocPg2)		goto out;	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)		goto out;	for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);	} out:	mutex_unlock(&ioc->sas_discovery_mutex);}/* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders *(Mutex UNLOCKED) */static void__mptsas_discovery_work(MPT_ADAPTER *ioc){	u32 handle = 0xFFFF;	ioc->sas_discovery_runtime=1;	mptsas_delete_expander_phys(ioc);	mptsas_probe_hba_phys(ioc);	while (!mptsas_probe_expander_phys(ioc, &handle))		;	ioc->sas_discovery_runtime=0;}/* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders *(Mutex LOCKED) */static voidmptsas_discovery_work(struct work_struct *work){	struct mptsas_discovery_event *ev =		container_of(work, struct mptsas_discovery_event, work);	MPT_ADAPTER *ioc = ev->ioc;	mutex_lock(&ioc->sas_discovery_mutex);	__mptsas_discovery_work(ioc);	mutex_unlock(&ioc->sas_discovery_mutex);	kfree(ev);}static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address){	struct mptsas_portinfo *port_info;	struct mptsas_phyinfo *phy_info = NULL;	int i;	mutex_lock(&ioc->sas_topology_mutex);	list_for_each_entry(port_info, &ioc->sas_topology, list) {		for (i = 0; i < port_info->num_phys; i++) {			if (!mptsas_is_end_device(				&port_info->phy_info[i].attached))				continue;			if (port_info->phy_info[i].attached.sas_address			    != sas_address)				continue;			phy_info = &port_info->phy_info[i];			break;		}	}	mutex_unlock(&ioc->sas_topology_mutex);	return phy_info;}static struct mptsas_phyinfo *mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u8 channel, u8 id){	struct mptsas_portinfo *port_info;	struct mptsas_phyinfo *phy_info = NULL;	int i;	mutex_lock(&ioc->sas_topology_mutex);	list_for_each_entry(port_info, &ioc->sas_topology, list) {		for (i = 0; i < port_info->num_phys; i++) {			if (!mptsas_is_end_device(				&port_info->phy_i

⌨️ 快捷键说明

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