[RFC] Preliminary expander support for aic94xx

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

 



This is dependent on the previously posted transport class expander
patch, but now it makes aic94xx handle expanders in a reasonable
fashion.

With this, the driver should be useable by almost all SAS (not SATA)
configurations ... as long as you don't try and remove it as a
module ...

James

diff --git a/drivers/scsi/sas/sas_discover.c b/drivers/scsi/sas/sas_discover.c
index c10b453..8b568ad 100644
--- a/drivers/scsi/sas/sas_discover.c
+++ b/drivers/scsi/sas/sas_discover.c
@@ -230,7 +230,21 @@ static int sas_get_port_device(struct sa
 
 	sas_init_dev(dev);
 
-	rphy = dev->dev_type == SAS_END_DEV ? sas_end_device_alloc(phy->phy) : sas_rphy_alloc(phy->phy);
+	switch (dev->dev_type) {
+	case SAS_END_DEV:
+		rphy = sas_end_device_alloc(phy->phy);
+		break;
+	case EDGE_DEV:
+		rphy = sas_expander_alloc(phy->phy, SAS_EDGE_EXPANDER_DEVICE);
+		break;
+	case FANOUT_DEV:
+		rphy = sas_expander_alloc(phy->phy, SAS_FANOUT_EXPANDER_DEVICE);
+		break;
+	default:
+		rphy = sas_rphy_alloc(phy->phy);
+		break;
+	}
+
 	if (!rphy) {
 		spin_unlock_irqrestore(&port->phy_list_lock, flags);
 		kfree(dev);
diff --git a/drivers/scsi/sas/sas_expander.c b/drivers/scsi/sas/sas_expander.c
index 0db6301..4713b19 100644
--- a/drivers/scsi/sas/sas_expander.c
+++ b/drivers/scsi/sas/sas_expander.c
@@ -142,6 +142,13 @@ static void sas_set_ex_phy(struct domain
 	struct ex_phy *phy = &ex->ex_phy[phy_id];
 	struct smp_resp *resp = disc_resp;
 	struct discover_resp *dr = &resp->disc;
+	struct sas_rphy *rphy = dev->rphy;
+
+	phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
+	dev_printk(KERN_ERR, &phy->phy->dev, "ALLOCATED\n\n");
+
+	/* FIXME: error_handling */
+	BUG_ON(!phy->phy);
 
 	switch (resp->result) {
 	case SMP_RESP_PHY_VACANT:
@@ -170,6 +177,33 @@ static void sas_set_ex_phy(struct domain
 	phy->virtual = dr->virtual;
 	phy->last_da_index = -1;
 
+	/* FIXME: This probably isn't right, but it will do for now*/
+	phy->phy->local_attached = 1;
+
+	phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
+	phy->phy->identify.target_port_protocols = phy->attached_tproto;
+	phy->phy->identify.phy_identifier = phy_id;
+	phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+	phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+	phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+	phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
+	switch (phy->linkrate) {
+	case PHY_LINKRATE_1_5:
+		phy->phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+		break;
+	case PHY_LINKRATE_3:
+		phy->phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+		break;
+	case PHY_LINKRATE_6:
+		phy->phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
+		break;
+	default:
+		phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+		break;
+	}
+
+	sas_phy_add(phy->phy);
+
 	SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
 		    SAS_ADDR(dev->sas_addr), phy->phy_id,
 		    phy->routing_attr == TABLE_ROUTING ? 'T' :
@@ -319,16 +353,19 @@ static inline void ex_assign_manuf_info(
 					*_mi_resp)
 {
 	u8 *mi_resp = _mi_resp;
+	struct sas_rphy *rphy = dev->rphy;
+	struct sas_expander_device *edev = rphy_to_expander_device(rphy);
 
-	memcpy(dev->ex_dev.vendor_id, mi_resp + 12, 8);
-	memcpy(dev->ex_dev.product_id, mi_resp + 20, 16);
-	memcpy(dev->ex_dev.product_rev, mi_resp + 36, 4);
+	memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
+	memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
+	memcpy(edev->product_rev, mi_resp + 36,
+	       SAS_EXPANDER_PRODUCT_REV_LEN);
 
 	if (mi_resp[8] & 1) {
-		memcpy(dev->ex_dev.component_vendor_id, mi_resp + 40, 8);
-		dev->ex_dev.component_id =
-			be16_to_cpu(*(__be16 *)(mi_resp + 48));
-		dev->ex_dev.component_revision_id = mi_resp[50];
+		memcpy(edev->component_vendor_id, mi_resp + 40,
+		       SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+		edev->component_id = mi_resp[48] << 8 | mi_resp[49];
+		edev->component_revision_id = mi_resp[50];
 	}
 }
 
@@ -501,6 +538,7 @@ static struct domain_device *sas_ex_disc
 	struct expander_device *parent_ex = &parent->ex_dev;
 	struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
 	struct domain_device *child = NULL;
+	struct sas_rphy *rphy;
 	int res;
 
 	if (phy->attached_sata_host || phy->attached_sata_ps)
@@ -519,6 +557,7 @@ static struct domain_device *sas_ex_disc
 
 	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
 		child->dev_type = SATA_DEV;
+		rphy = sas_rphy_alloc(phy->phy);
 		if (phy->attached_tproto & SAS_PROTO_STP)
 			child->tproto = phy->attached_tproto;
 		if (phy->attached_sata_dev)
@@ -546,8 +585,23 @@ static struct domain_device *sas_ex_disc
 		}
 	} else if (phy->attached_tproto & SAS_PROTO_SSP) {
 		child->dev_type = SAS_END_DEV;
+		rphy = sas_end_device_alloc(phy->phy);
+		/* FIXME: error handling */
+		BUG_ON(!rphy);
 		child->tproto = phy->attached_tproto;
 		sas_init_dev(child);
+
+		child->rphy = rphy;
+		rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
+		rphy->identify.device_type = SAS_END_DEVICE;
+		rphy->identify.sas_address = SAS_ADDR(child->sas_addr);
+		rphy->identify.initiator_port_protocols = child->iproto;
+		rphy->identify.target_port_protocols = child->tproto;
+
+		spin_lock(&parent->port->dev_list_lock);
+		list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+		spin_unlock(&parent->port->dev_list_lock);
+
 		res = sas_discover_end_dev(child);
 		if (res) {
 			SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
@@ -561,7 +615,9 @@ static struct domain_device *sas_ex_disc
 		SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
 			    phy->attached_tproto, SAS_ADDR(parent->sas_addr),
 			    phy_id);
+		rphy = sas_rphy_alloc(phy->phy);
 	}
+
 	list_add_tail(&child->siblings, &parent_ex->children);
 	return child;
 }
@@ -569,9 +625,11 @@ static struct domain_device *sas_ex_disc
 static struct domain_device *sas_ex_discover_expander(
 	struct domain_device *parent, int phy_id)
 {
-	struct expander_device *parent_ex = &parent->ex_dev;
-	struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
+	struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
+	struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
 	struct domain_device *child = NULL;
+	struct sas_rphy *rphy;
+	struct sas_expander_device *edev;
 	int res;
 
 	if (phy->routing_attr == DIRECT_ROUTING) {
@@ -585,6 +643,19 @@ static struct domain_device *sas_ex_disc
 	child = kzalloc(sizeof(*child), GFP_KERNEL);
 	if (!child)
 		return NULL;
+	switch (phy->attached_dev_type) {
+	case EDGE_DEV:
+		rphy = sas_expander_alloc(phy->phy, SAS_EDGE_EXPANDER_DEVICE);
+		break;
+	case FANOUT_DEV:
+		rphy = sas_expander_alloc(phy->phy, SAS_FANOUT_EXPANDER_DEVICE);
+		break;
+	default:
+		rphy = NULL;	/* shut gcc up */
+		BUG();
+	}
+	child->rphy = rphy;
+	edev = rphy_to_expander_device(rphy);
 	child->dev_type = phy->attached_dev_type;
 	child->parent = parent;
 	child->port = parent->port;
@@ -593,16 +664,15 @@ static struct domain_device *sas_ex_disc
 	memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
 	sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
 	sas_ex_get_linkrate(parent, child, phy);
-	child->ex_dev.level = parent_ex->level + 1;
+	edev->level = parent_ex->level + 1;
 	parent->port->disc.max_level = max(parent->port->disc.max_level,
-					   child->ex_dev.level);
+					   edev->level);
 	sas_init_dev(child);
 	res = sas_discover_expander(child);
 	if (res) {
 		kfree(child);
 		return NULL;
 	}
-	list_add_tail(&child->siblings, &parent_ex->children);
 	return child;
 }
 
@@ -1248,7 +1318,8 @@ static int sas_ex_level_discovery(struct
 	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
 		if (dev->dev_type == EDGE_DEV ||
 		    dev->dev_type == FANOUT_DEV) {
-			struct expander_device *ex = &dev->ex_dev;
+			struct sas_expander_device *ex =
+				rphy_to_expander_device(dev->rphy);
 
 			if (level == ex->level)
 				res = sas_ex_discover_devices(dev, -1);
@@ -1275,8 +1346,11 @@ static int sas_ex_bfs_disc(struct sas_po
 int sas_discover_root_expander(struct domain_device *dev)
 {
 	int res;
+	struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+
+	sas_rphy_add(dev->rphy);
 
-	dev->ex_dev.level = dev->port->disc.max_level; /* 0 */
+	ex->level = dev->port->disc.max_level; /* 0 */
 	res = sas_discover_expander(dev);
 	if (!res)
 		sas_ex_bfs_disc(dev->port);
@@ -1482,7 +1556,8 @@ static int sas_discover_bfs_by_root_leve
 	list_for_each_entry(child, &ex_root->children, siblings) {
 		if (child->dev_type == EDGE_DEV ||
 		    child->dev_type == FANOUT_DEV) {
-			struct expander_device *ex = &child->ex_dev;
+			struct sas_expander_device *ex =
+				rphy_to_expander_device(child->rphy);
 
 			if (level > ex->level)
 				res = sas_discover_bfs_by_root_level(child,
@@ -1497,7 +1572,8 @@ static int sas_discover_bfs_by_root_leve
 static int sas_discover_bfs_by_root(struct domain_device *dev)
 {
 	int res;
-	int level = dev->ex_dev.level+1;
+	struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+	int level = ex->level+1;
 
 	res = sas_ex_discover_devices(dev, -1);
 	if (res)
diff --git a/include/scsi/sas/sas_expander.h b/include/scsi/sas/sas_expander.h
index bd00e1c..e83b41c 100644
--- a/include/scsi/sas/sas_expander.h
+++ b/include/scsi/sas/sas_expander.h
@@ -70,13 +70,13 @@ struct ex_phy {
 	u8   virtual:1;
 
 	int  last_da_index;
+
+	struct sas_phy *phy;
 };
 
 struct expander_device {
 	struct list_head children;
 
-	int    level;
-
 	u16    ex_change_count;
 	u16    max_route_indexes;
 	u8     num_phys;
@@ -84,20 +84,7 @@ struct expander_device {
 	u8     conf_route_table:1;
 	u8     enclosure_logical_id[8];
 
-	char   vendor_id[8+1];
-	char   product_id[16+1];
-	char   product_rev[4+1];
-	char   component_vendor_id[8+1];
-	u16    component_id;
-	u8     component_revision_id;
-
 	struct ex_phy *ex_phy;
-
-	struct bin_attribute smp_bin_attr;
-	void *smp_req;
-	int   smp_req_size;
-	int   smp_portal_pid;
-	struct semaphore smp_sema;
 };
 
 int  sas_discover_root_expander(struct domain_device *dev);


-
: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux