sas_port.c

来自「linux 内核源代码」· C语言 代码 · 共 292 行

C
292
字号
/* * Serial Attached SCSI (SAS) Port class * * Copyright (C) 2005 Adaptec, Inc.  All rights reserved. * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> * * This file is licensed under GPLv2. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA * */#include "sas_internal.h"#include <scsi/scsi_transport.h>#include <scsi/scsi_transport_sas.h>#include "../scsi_sas_internal.h"/** * sas_form_port -- add this phy to a port * @phy: the phy of interest * * This function adds this phy to an existing port, thus creating a wide * port, or it creates a port and adds the phy to the port. */static void sas_form_port(struct asd_sas_phy *phy){	int i;	struct sas_ha_struct *sas_ha = phy->ha;	struct asd_sas_port *port = phy->port;	struct sas_internal *si =		to_sas_internal(sas_ha->core.shost->transportt);	unsigned long flags;	if (port) {		if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,			   SAS_ADDR_SIZE) != 0)			sas_deform_port(phy);		else {			SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",				    __FUNCTION__, phy->id, phy->port->id,				    phy->port->num_phys);			return;		}	}	/* find a port */	spin_lock_irqsave(&sas_ha->phy_port_lock, flags);	for (i = 0; i < sas_ha->num_phys; i++) {		port = sas_ha->sas_port[i];		spin_lock(&port->phy_list_lock);		if (*(u64 *) port->sas_addr &&		    memcmp(port->attached_sas_addr,			   phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&		    port->num_phys > 0) {			/* wide port */			SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,				    port->id);			break;		} else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {			memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);			break;		}		spin_unlock(&port->phy_list_lock);	}	if (i >= sas_ha->num_phys) {		printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",		       __FUNCTION__);		spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);		return;	}	/* add the phy to the port */	list_add_tail(&phy->port_phy_el, &port->phy_list);	phy->port = port;	port->num_phys++;	port->phy_mask |= (1U << phy->id);	if (!port->phy)		port->phy = phy->phy;	SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,		    port->id, port->phy_mask);	if (*(u64 *)port->attached_sas_addr == 0) {		port->class = phy->class;		memcpy(port->attached_sas_addr, phy->attached_sas_addr,		       SAS_ADDR_SIZE);		port->iproto = phy->iproto;		port->tproto = phy->tproto;		port->oob_mode = phy->oob_mode;		port->linkrate = phy->linkrate;	} else		port->linkrate = max(port->linkrate, phy->linkrate);	spin_unlock(&port->phy_list_lock);	spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);	if (!port->port) {		port->port = sas_port_alloc(phy->phy->dev.parent, port->id);		BUG_ON(!port->port);		sas_port_add(port->port);	}	sas_port_add_phy(port->port, phy->phy);	if (port->port_dev)		port->port_dev->pathways = port->num_phys;	/* Tell the LLDD about this port formation. */	if (si->dft->lldd_port_formed)		si->dft->lldd_port_formed(phy);	sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);}/** * sas_deform_port -- remove this phy from the port it belongs to * @phy: the phy of interest * * This is called when the physical link to the other phy has been * lost (on this phy), in Event thread context. We cannot delay here. */void sas_deform_port(struct asd_sas_phy *phy){	struct sas_ha_struct *sas_ha = phy->ha;	struct asd_sas_port *port = phy->port;	struct sas_internal *si =		to_sas_internal(sas_ha->core.shost->transportt);	unsigned long flags;	if (!port)		return;		  /* done by a phy event */	if (port->port_dev)		port->port_dev->pathways--;	if (port->num_phys == 1) {		sas_unregister_domain_devices(port);		sas_port_delete(port->port);		port->port = NULL;	} else		sas_port_delete_phy(port->port, phy->phy);	if (si->dft->lldd_port_deformed)		si->dft->lldd_port_deformed(phy);	spin_lock_irqsave(&sas_ha->phy_port_lock, flags);	spin_lock(&port->phy_list_lock);	list_del_init(&phy->port_phy_el);	phy->port = NULL;	port->num_phys--;	port->phy_mask &= ~(1U << phy->id);	if (port->num_phys == 0) {		INIT_LIST_HEAD(&port->phy_list);		memset(port->sas_addr, 0, SAS_ADDR_SIZE);		memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);		port->class = 0;		port->iproto = 0;		port->tproto = 0;		port->oob_mode = 0;		port->phy_mask = 0;	}	spin_unlock(&port->phy_list_lock);	spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);	return;}/* ---------- SAS port events ---------- */void sas_porte_bytes_dmaed(struct work_struct *work){	struct asd_sas_event *ev =		container_of(work, struct asd_sas_event, work);	struct asd_sas_phy *phy = ev->phy;	sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,			&phy->port_events_pending);	sas_form_port(phy);}void sas_porte_broadcast_rcvd(struct work_struct *work){	struct asd_sas_event *ev =		container_of(work, struct asd_sas_event, work);	struct asd_sas_phy *phy = ev->phy;	unsigned long flags;	u32 prim;	sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,			&phy->port_events_pending);	spin_lock_irqsave(&phy->sas_prim_lock, flags);	prim = phy->sas_prim;	spin_unlock_irqrestore(&phy->sas_prim_lock, flags);	SAS_DPRINTK("broadcast received: %d\n", prim);	sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);}void sas_porte_link_reset_err(struct work_struct *work){	struct asd_sas_event *ev =		container_of(work, struct asd_sas_event, work);	struct asd_sas_phy *phy = ev->phy;	sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,			&phy->port_events_pending);	sas_deform_port(phy);}void sas_porte_timer_event(struct work_struct *work){	struct asd_sas_event *ev =		container_of(work, struct asd_sas_event, work);	struct asd_sas_phy *phy = ev->phy;	sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,			&phy->port_events_pending);	sas_deform_port(phy);}void sas_porte_hard_reset(struct work_struct *work){	struct asd_sas_event *ev =		container_of(work, struct asd_sas_event, work);	struct asd_sas_phy *phy = ev->phy;	sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,			&phy->port_events_pending);	sas_deform_port(phy);}/* ---------- SAS port registration ---------- */static void sas_init_port(struct asd_sas_port *port,			  struct sas_ha_struct *sas_ha, int i){	port->id = i;	INIT_LIST_HEAD(&port->dev_list);	spin_lock_init(&port->phy_list_lock);	INIT_LIST_HEAD(&port->phy_list);	port->num_phys = 0;	port->phy_mask = 0;	port->ha = sas_ha;	spin_lock_init(&port->dev_list_lock);}int sas_register_ports(struct sas_ha_struct *sas_ha){	int i;	/* initialize the ports and discovery */	for (i = 0; i < sas_ha->num_phys; i++) {		struct asd_sas_port *port = sas_ha->sas_port[i];		sas_init_port(port, sas_ha, i);		sas_init_disc(&port->disc, port);	}	return 0;}void sas_unregister_ports(struct sas_ha_struct *sas_ha){	int i;	for (i = 0; i < sas_ha->num_phys; i++)		if (sas_ha->sas_phy[i]->port)			sas_deform_port(sas_ha->sas_phy[i]);}

⌨️ 快捷键说明

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