[PATCH 2.6.13 13/14] sas-class: sas_port.c SAS Port (events, attrs, initialization)

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Luben Tuikov <[email protected]>

diff -X linux-2.6.13/Documentation/dontdiff -Naur linux-2.6.13-orig/drivers/scsi/sas-class/sas_port.c linux-2.6.13/drivers/scsi/sas-class/sas_port.c
--- linux-2.6.13-orig/drivers/scsi/sas-class/sas_port.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.13/drivers/scsi/sas-class/sas_port.c	2005-09-09 11:50:35.000000000 -0400
@@ -0,0 +1,430 @@
+/*
+ * Serial Attached SCSI (SAS) Port class
+ *
+ * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <[email protected]>
+ *
+ * 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
+ *
+ * $Id: //depot/sas-class/sas_port.c#41 $
+ */
+
+#include "sas_internal.h"
+#include <scsi/sas/sas_discover.h>
+
+/* called only when num_phys increments, afterwards */
+static void sas_create_port_sysfs_links(struct sas_phy *phy)
+{
+	struct sas_port *port = phy->port;
+
+	if (port->num_phys == 1) {
+		kobject_register(&port->port_kobj);
+		kset_register(&port->phy_kset);
+		kset_register(&port->dev_kset);
+	}
+	/* add port->phy link */
+	sysfs_create_link(&port->phy_kset.kobj, &phy->phy_kobj,
+			  kobject_name(&phy->phy_kobj));
+	/* add phy->port link */
+	sysfs_create_link(&phy->phy_kobj, &port->port_kobj, "port");
+}
+
+/* called only when num_phys decrements, just before it does */
+static void sas_remove_port_sysfs_links(struct sas_phy *phy)
+{
+	struct sas_port *port = phy->port;
+
+	/* remove phy->port link */
+	sysfs_remove_link(&phy->phy_kobj, "port");
+	/* remove port to phy link */
+	sysfs_remove_link(&port->phy_kset.kobj, kobject_name(&phy->phy_kobj));
+
+	if (port->num_phys == 1) {
+		kset_unregister(&port->dev_kset);
+		kset_unregister(&port->phy_kset);
+		kobject_unregister(&port->port_kobj);
+	}
+}
+
+/**
+ * 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 sas_phy *phy)
+{
+	int i;
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_port *port = phy->port;
+
+	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(&sas_ha->phy_port_lock);
+	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(&sas_ha->phy_port_lock);
+		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);
+
+	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(&sas_ha->phy_port_lock);
+
+	if (port->port_dev)
+		port->port_dev->pathways = port->num_phys;
+	
+	sas_create_port_sysfs_links(phy);
+	/* Tell the LLDD about this port formation. */
+	if (sas_ha->lldd_port_formed)
+		sas_ha->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 sas_phy *phy)
+{
+	struct sas_ha_struct *sas_ha = phy->ha;
+	struct sas_port *port = phy->port;
+
+	if (!port)
+		return;		  /* done by a phy event */
+
+	if (port->port_dev)
+		port->port_dev->pathways--;
+
+	if (port->num_phys == 1) {
+		init_completion(&port->port_gone_completion);
+		sas_discover_event(port, DISCE_PORT_GONE);
+		wait_for_completion(&port->port_gone_completion);
+	}
+
+	if (sas_ha->lldd_port_deformed)
+		sas_ha->lldd_port_deformed(phy);
+
+	sas_remove_port_sysfs_links(phy);
+
+	spin_lock(&sas_ha->phy_port_lock);
+	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(&sas_ha->phy_port_lock);
+
+	return;
+}
+
+/* ---------- SAS port events ---------- */
+
+void sas_porte_bytes_dmaed(struct sas_phy *phy)
+{
+	sas_form_port(phy);
+}
+
+void sas_porte_broadcast_rcvd(struct sas_phy *phy)
+{
+	unsigned long flags;
+	u32 prim;
+	
+	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 sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+void sas_porte_timer_event(struct sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+void sas_porte_hard_reset(struct sas_phy *phy)
+{
+	sas_deform_port(phy);
+}
+
+/* ---------- SAS port attributes ---------- */
+
+static ssize_t sas_port_id_show(struct sas_port *port, char *buf)
+{
+	return sprintf(buf, "%d\n", port->id);
+}
+
+static ssize_t sas_port_class_show(struct sas_port *port, char *buf)
+{
+	return sas_show_class(port->class, buf);
+}
+
+static ssize_t sas_port_sas_addr_show(struct sas_port *port, char *buf)
+{
+	return sprintf(buf, "%llx\n", SAS_ADDR(port->sas_addr));
+}
+
+static ssize_t sas_port_attached_sas_addr_show(struct sas_port *port,char *buf)
+{
+	return sprintf(buf, "%llx\n", SAS_ADDR(port->attached_sas_addr));
+}
+
+static ssize_t sas_port_iproto_show(struct sas_port *port, char *buf)
+{
+	return sas_show_proto(port->iproto, buf);
+}
+
+static ssize_t sas_port_tproto_show(struct sas_port *port, char *buf)
+{
+	return sas_show_proto(port->tproto, buf);
+}
+
+static ssize_t sas_port_oob_mode_show(struct sas_port *port, char *buf)
+{
+	return sas_show_oob_mode(port->oob_mode, buf);
+}
+
+struct port_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct sas_port *port, char *);
+	ssize_t (*store)(struct sas_port *port, const char *, size_t);
+};
+
+static struct port_attribute port_attrs[] = {
+	__ATTR(id, 0444, sas_port_id_show, NULL),
+	__ATTR(class, 0444, sas_port_class_show, NULL),
+	__ATTR(port_identifier, 0444, sas_port_sas_addr_show, NULL),
+	__ATTR(attached_port_identifier, 0444, sas_port_attached_sas_addr_show, NULL),
+	__ATTR(iproto, 0444, sas_port_iproto_show, NULL),
+	__ATTR(tproto, 0444, sas_port_tproto_show, NULL),	
+	__ATTR(oob_mode, 0444, sas_port_oob_mode_show, NULL),
+	__ATTR_NULL,
+};
+
+static struct attribute *def_attrs[ARRAY_SIZE(port_attrs)];
+
+#define to_sas_port(_obj) container_of(_obj, struct sas_port, port_kobj)
+#define to_port_attr(_attr) container_of(_attr, struct port_attribute, attr)
+
+static ssize_t port_show_attr(struct kobject *kobj, struct attribute *attr,
+			      char *page)
+{
+	ssize_t ret = 0;
+	struct sas_port *port = to_sas_port(kobj);
+	struct port_attribute *port_attr = to_port_attr(attr);
+
+	if (port_attr->show)
+		ret = port_attr->show(port, page);
+	return ret;
+}
+
+static struct sysfs_ops port_sysfs_ops = {
+	.show = port_show_attr,
+};
+
+static struct kobj_type port_type = {
+	.sysfs_ops = &port_sysfs_ops,
+	.default_attrs = def_attrs,
+};
+
+/* ---------- SAS port registration ---------- */
+
+static void sas_init_port(struct sas_port *port,
+			  struct sas_ha_struct *sas_ha, int i,
+			  struct kset *parent_kset)
+{
+	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;
+
+	memset(&port->port_kobj, 0, sizeof(port->port_kobj));
+	memset(&port->phy_kset, 0, sizeof(port->phy_kset));
+	memset(&port->dev_kset, 0, sizeof(port->dev_kset));
+		
+	kobject_set_name(&port->port_kobj, "%d", port->id);
+	port->port_kobj.kset = parent_kset;
+	port->port_kobj.ktype= parent_kset->ktype;
+
+	kobject_set_name(&port->phy_kset.kobj, "%s", "phys");
+	port->phy_kset.kobj.parent = &port->port_kobj;
+	port->phy_kset.ktype = NULL;
+
+	kobject_set_name(&port->dev_kset.kobj, "%s", "domain");
+	port->dev_kset.kobj.parent = &port->port_kobj;
+	port->dev_kset.ktype = NULL;
+
+	port->id_map.max_ids = 128;
+	port->id_map.id_bitmap_size =
+		BITS_TO_LONGS(port->id_map.max_ids)*sizeof(long);
+	port->id_map.id_bitmap = kmalloc(port->id_map.id_bitmap_size,
+					 GFP_KERNEL);
+	memset(port->id_map.id_bitmap, 0, port->id_map.id_bitmap_size);
+	spin_lock_init(&port->id_map.id_bitmap_lock);
+}
+
+int sas_register_ports(struct sas_ha_struct *sas_ha)
+{
+	int i;
+	
+	for (i = 0; i < ARRAY_SIZE(def_attrs)-1; i++)
+		def_attrs[i] = &port_attrs[i].attr;
+	def_attrs[i] = NULL;
+
+	/* make sas/ha/ports/ appear */
+	kobject_set_name(&sas_ha->port_kset.kobj, "%s", "ports");
+	sas_ha->port_kset.kobj.kset = &sas_ha->ha_kset; /* parent */
+	/* no type inheritance */
+	sas_ha->port_kset.kobj.ktype = NULL;
+	sas_ha->port_kset.ktype = &port_type; /* children are of this type */
+
+	/* initialize the ports and discovery */
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		struct sas_port *port = sas_ha->sas_port[i];
+
+		sas_init_port(port, sas_ha, i, &sas_ha->port_kset);
+		sas_init_disc(&port->disc, port);
+	}
+
+	return kset_register(&sas_ha->port_kset);
+}
+
+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]);
+
+	for (i = 0; i < sas_ha->num_phys; i++) {
+		kfree(sas_ha->sas_port[i]->id_map.id_bitmap);
+		sas_ha->sas_port[i]->id_map.id_bitmap = NULL;
+	}
+
+	kset_unregister(&sas_ha->port_kset);
+}
+
+int sas_reserve_free_id(struct sas_port *port)
+{
+	int id;
+
+	spin_lock(&port->id_map.id_bitmap_lock);
+	id = find_first_zero_bit(port->id_map.id_bitmap, port->id_map.max_ids);
+	if (id >= port->id_map.max_ids) {
+		id = -ENOMEM;
+		spin_unlock(&port->id_map.id_bitmap_lock);
+		goto out;
+	}
+	set_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+out:
+	return id;
+}
+
+void sas_reserve_scsi_id(struct sas_port *port, int id)
+{
+	if (0 > id || id >= port->id_map.max_ids)
+		return;
+	spin_lock(&port->id_map.id_bitmap_lock);
+	set_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+}
+
+void sas_release_scsi_id(struct sas_port *port, int id)
+{
+	if (0 > id || id >= port->id_map.max_ids)
+		return;
+	spin_lock(&port->id_map.id_bitmap_lock);
+	clear_bit(id, port->id_map.id_bitmap);
+	spin_unlock(&port->id_map.id_bitmap_lock);
+}


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]
  Powered by Linux