diff options
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_expander.c | 83 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_init.c | 42 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_phy.c | 7 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_port.c | 24 |
5 files changed, 98 insertions, 60 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 6f93fee2b21b..1ecca71df8b5 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c @@ -281,7 +281,7 @@ int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) res = sas_get_report_phy_sata(dev->parent, phy->phy_id, &dev->sata_dev.rps_resp); if (res) { - pr_debug("report phy sata to %016llx:0x%x returned 0x%x\n", + pr_debug("report phy sata to %016llx:%02d returned 0x%x\n", SAS_ADDR(dev->parent->sas_addr), phy->phy_id, res); return res; diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 17b45a0c7bc3..83f2fd70ce76 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -826,9 +826,14 @@ static struct domain_device *sas_ex_discover_end_dev( #ifdef CONFIG_SCSI_SAS_ATA if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { if (child->linkrate > parent->min_linkrate) { + struct sas_phy *cphy = child->phy; + enum sas_linkrate min_prate = cphy->minimum_linkrate, + parent_min_lrate = parent->min_linkrate, + min_linkrate = (min_prate > parent_min_lrate) ? + parent_min_lrate : 0; struct sas_phy_linkrates rates = { .maximum_linkrate = parent->min_linkrate, - .minimum_linkrate = parent->min_linkrate, + .minimum_linkrate = min_linkrate, }; int ret; @@ -865,7 +870,7 @@ static struct domain_device *sas_ex_discover_end_dev( res = sas_discover_sata(child); if (res) { - pr_notice("sas_discover_sata() for device %16llx at %016llx:0x%x returned 0x%x\n", + pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); goto out_list_del; @@ -890,7 +895,7 @@ static struct domain_device *sas_ex_discover_end_dev( res = sas_discover_end_dev(child); if (res) { - pr_notice("sas_discover_end_dev() for device %16llx at %016llx:0x%x returned 0x%x\n", + pr_notice("sas_discover_end_dev() for device %16llx at %016llx:%02d returned 0x%x\n", SAS_ADDR(child->sas_addr), SAS_ADDR(parent->sas_addr), phy_id, res); goto out_list_del; @@ -955,7 +960,7 @@ static struct domain_device *sas_ex_discover_expander( int res; if (phy->routing_attr == DIRECT_ROUTING) { - pr_warn("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not allowed\n", + pr_warn("ex %016llx:%02d:D <--> ex %016llx:0x%x is not allowed\n", SAS_ADDR(parent->sas_addr), phy_id, SAS_ADDR(phy->attached_sas_addr), phy->attached_phy_id); @@ -1065,7 +1070,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) ex_phy->attached_dev_type != SAS_FANOUT_EXPANDER_DEVICE && ex_phy->attached_dev_type != SAS_EDGE_EXPANDER_DEVICE && ex_phy->attached_dev_type != SAS_SATA_PENDING) { - pr_warn("unknown device type(0x%x) attached to ex %016llx phy 0x%x\n", + pr_warn("unknown device type(0x%x) attached to ex %016llx phy%02d\n", ex_phy->attached_dev_type, SAS_ADDR(dev->sas_addr), phy_id); @@ -1081,7 +1086,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) } if (sas_ex_join_wide_port(dev, phy_id)) { - pr_debug("Attaching ex phy%d to wide port %016llx\n", + pr_debug("Attaching ex phy%02d to wide port %016llx\n", phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); return res; } @@ -1093,7 +1098,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) break; case SAS_FANOUT_EXPANDER_DEVICE: if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) { - pr_debug("second fanout expander %016llx phy 0x%x attached to ex %016llx phy 0x%x\n", + pr_debug("second fanout expander %016llx phy%02d attached to ex %016llx phy%02d\n", SAS_ADDR(ex_phy->attached_sas_addr), ex_phy->attached_phy_id, SAS_ADDR(dev->sas_addr), @@ -1126,7 +1131,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) SAS_ADDR(child->sas_addr)) { ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; if (sas_ex_join_wide_port(dev, i)) - pr_debug("Attaching ex phy%d to wide port %016llx\n", + pr_debug("Attaching ex phy%02d to wide port %016llx\n", i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); } } @@ -1151,7 +1156,7 @@ static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr) phy->attached_dev_type == SAS_FANOUT_EXPANDER_DEVICE) && phy->routing_attr == SUBTRACTIVE_ROUTING) { - memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE); + memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); return 1; } @@ -1163,7 +1168,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) { struct expander_device *ex = &dev->ex_dev; struct domain_device *child; - u8 sub_addr[8] = {0, }; + u8 sub_addr[SAS_ADDR_SIZE] = {0, }; list_for_each_entry(child, &ex->children, siblings) { if (child->dev_type != SAS_EDGE_EXPANDER_DEVICE && @@ -1173,7 +1178,7 @@ static int sas_check_level_subtractive_boundary(struct domain_device *dev) sas_find_sub_addr(child, sub_addr); continue; } else { - u8 s2[8]; + u8 s2[SAS_ADDR_SIZE]; if (sas_find_sub_addr(child, s2) && (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) { @@ -1261,7 +1266,7 @@ static int sas_check_ex_subtractive_boundary(struct domain_device *dev) else if (SAS_ADDR(sub_sas_addr) != SAS_ADDR(phy->attached_sas_addr)) { - pr_notice("ex %016llx phy 0x%x diverges(%016llx) on subtractive boundary(%016llx). Disabled\n", + pr_notice("ex %016llx phy%02d diverges(%016llx) on subtractive boundary(%016llx). Disabled\n", SAS_ADDR(dev->sas_addr), i, SAS_ADDR(phy->attached_sas_addr), SAS_ADDR(sub_sas_addr)); @@ -1282,7 +1287,7 @@ static void sas_print_parent_topology_bug(struct domain_device *child, }; struct domain_device *parent = child->parent; - pr_notice("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x has %c:%c routing link!\n", + pr_notice("%s ex %016llx phy%02d <--> %s ex %016llx phy%02d has %c:%c routing link!\n", ex_type[parent->dev_type], SAS_ADDR(parent->sas_addr), parent_phy->phy_id, @@ -1304,7 +1309,7 @@ static int sas_check_eeds(struct domain_device *child, if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) { res = -ENODEV; - pr_warn("edge ex %016llx phy S:0x%x <--> edge ex %016llx phy S:0x%x, while there is a fanout ex %016llx\n", + pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n", SAS_ADDR(parent->sas_addr), parent_phy->phy_id, SAS_ADDR(child->sas_addr), @@ -1327,7 +1332,7 @@ static int sas_check_eeds(struct domain_device *child, ; else { res = -ENODEV; - pr_warn("edge ex %016llx phy 0x%x <--> edge ex %016llx phy 0x%x link forms a third EEDS!\n", + pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n", SAS_ADDR(parent->sas_addr), parent_phy->phy_id, SAS_ADDR(child->sas_addr), @@ -1445,11 +1450,11 @@ static int sas_configure_present(struct domain_device *dev, int phy_id, goto out; res = rri_resp[2]; if (res == SMP_RESP_NO_INDEX) { - pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n", + pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n", SAS_ADDR(dev->sas_addr), phy_id, i); goto out; } else if (res != SMP_RESP_FUNC_ACC) { - pr_notice("%s: dev %016llx phy 0x%x index 0x%x result 0x%x\n", + pr_notice("%s: dev %016llx phy%02d index 0x%x result 0x%x\n", __func__, SAS_ADDR(dev->sas_addr), phy_id, i, res); goto out; @@ -1515,7 +1520,7 @@ static int sas_configure_set(struct domain_device *dev, int phy_id, goto out; res = cri_resp[2]; if (res == SMP_RESP_NO_INDEX) { - pr_warn("overflow of indexes: dev %016llx phy 0x%x index 0x%x\n", + pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n", SAS_ADDR(dev->sas_addr), phy_id, index); } out: @@ -1760,10 +1765,11 @@ static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, res = sas_get_phy_discover(dev, phy_id, disc_resp); if (res == 0) { - memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8); + memcpy(sas_addr, disc_resp->disc.attached_sas_addr, + SAS_ADDR_SIZE); *type = to_dev_type(dr); if (*type == 0) - memset(sas_addr, 0, 8); + memset(sas_addr, 0, SAS_ADDR_SIZE); } kfree(disc_resp); return res; @@ -1870,10 +1876,12 @@ static int sas_find_bcast_dev(struct domain_device *dev, if (phy_id != -1) { *src_dev = dev; ex->ex_change_count = ex_change_count; - pr_info("Expander phy change count has changed\n"); + pr_info("ex %016llx phy%02d change count has changed\n", + SAS_ADDR(dev->sas_addr), phy_id); return res; } else - pr_info("Expander phys DID NOT change\n"); + pr_info("ex %016llx phys DID NOT change\n", + SAS_ADDR(dev->sas_addr)); } list_for_each_entry(ch, &ex->children, siblings) { if (ch->dev_type == SAS_EDGE_EXPANDER_DEVICE || ch->dev_type == SAS_FANOUT_EXPANDER_DEVICE) { @@ -1983,7 +1991,7 @@ static int sas_discover_new(struct domain_device *dev, int phy_id) struct domain_device *child; int res; - pr_debug("ex %016llx phy%d new device attached\n", + pr_debug("ex %016llx phy%02d new device attached\n", SAS_ADDR(dev->sas_addr), phy_id); res = sas_ex_phy_discover(dev, phy_id); if (res) @@ -2022,15 +2030,23 @@ static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old) return false; } -static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) +static int sas_rediscover_dev(struct domain_device *dev, int phy_id, + bool last, int sibling) { struct expander_device *ex = &dev->ex_dev; struct ex_phy *phy = &ex->ex_phy[phy_id]; enum sas_device_type type = SAS_PHY_UNUSED; - u8 sas_addr[8]; + u8 sas_addr[SAS_ADDR_SIZE]; + char msg[80] = ""; int res; - memset(sas_addr, 0, 8); + if (!last) + sprintf(msg, ", part of a wide port with phy%02d", sibling); + + pr_debug("ex %016llx rediscovering phy%02d%s\n", + SAS_ADDR(dev->sas_addr), phy_id, msg); + + memset(sas_addr, 0, SAS_ADDR_SIZE); res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type); switch (res) { case SMP_RESP_NO_PHY: @@ -2052,6 +2068,11 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) { phy->phy_state = PHY_EMPTY; sas_unregister_devs_sas_addr(dev, phy_id, last); + /* + * Even though the PHY is empty, for convenience we discover + * the PHY to update the PHY info, like negotiated linkrate. + */ + sas_ex_phy_discover(dev, phy_id); return res; } else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) && dev_type_flutter(type, phy->attached_dev_type)) { @@ -2062,13 +2083,13 @@ static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING) action = ", needs recovery"; - pr_debug("ex %016llx phy 0x%x broadcast flutter%s\n", + pr_debug("ex %016llx phy%02d broadcast flutter%s\n", SAS_ADDR(dev->sas_addr), phy_id, action); return res; } /* we always have to delete the old device when we went here */ - pr_info("ex %016llx phy 0x%x replace %016llx\n", + pr_info("ex %016llx phy%02d replace %016llx\n", SAS_ADDR(dev->sas_addr), phy_id, SAS_ADDR(phy->attached_sas_addr)); sas_unregister_devs_sas_addr(dev, phy_id, last); @@ -2098,7 +2119,7 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) int i; bool last = true; /* is this the last phy of the port */ - pr_debug("ex %016llx phy%d originated BROADCAST(CHANGE)\n", + pr_debug("ex %016llx phy%02d originated BROADCAST(CHANGE)\n", SAS_ADDR(dev->sas_addr), phy_id); if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) { @@ -2109,13 +2130,11 @@ static int sas_rediscover(struct domain_device *dev, const int phy_id) continue; if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(changed_phy->attached_sas_addr)) { - pr_debug("phy%d part of wide port with phy%d\n", - phy_id, i); last = false; break; } } - res = sas_rediscover_dev(dev, phy_id, last); + res = sas_rediscover_dev(dev, phy_id, last, i); } else res = sas_discover_new(dev, phy_id); return res; diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c index 221340ee8651..28a460c36c0b 100644 --- a/drivers/scsi/libsas/sas_init.c +++ b/drivers/scsi/libsas/sas_init.c @@ -87,25 +87,27 @@ EXPORT_SYMBOL_GPL(sas_free_task); /*------------ SAS addr hash -----------*/ void sas_hash_addr(u8 *hashed, const u8 *sas_addr) { - const u32 poly = 0x00DB2777; - u32 r = 0; - int i; - - for (i = 0; i < 8; i++) { - int b; - for (b = 7; b >= 0; b--) { - r <<= 1; - if ((1 << b) & sas_addr[i]) { - if (!(r & 0x01000000)) - r ^= poly; - } else if (r & 0x01000000) - r ^= poly; - } - } - - hashed[0] = (r >> 16) & 0xFF; - hashed[1] = (r >> 8) & 0xFF ; - hashed[2] = r & 0xFF; + const u32 poly = 0x00DB2777; + u32 r = 0; + int i; + + for (i = 0; i < SAS_ADDR_SIZE; i++) { + int b; + + for (b = (SAS_ADDR_SIZE - 1); b >= 0; b--) { + r <<= 1; + if ((1 << b) & sas_addr[i]) { + if (!(r & 0x01000000)) + r ^= poly; + } else if (r & 0x01000000) { + r ^= poly; + } + } + } + + hashed[0] = (r >> 16) & 0xFF; + hashed[1] = (r >> 8) & 0xFF; + hashed[2] = r & 0xFF; } int sas_register_ha(struct sas_ha_struct *sas_ha) @@ -623,7 +625,7 @@ struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy) if (atomic_read(&phy->event_nr) > phy->ha->event_thres) { if (i->dft->lldd_control_phy) { if (cmpxchg(&phy->in_shutdown, 0, 1) == 0) { - pr_notice("The phy%02d bursting events, shut it down.\n", + pr_notice("The phy%d bursting events, shut it down.\n", phy->id); sas_notify_phy_event(phy, PHYE_SHUTDOWN); } diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c index 0374243c85d0..e030e1452136 100644 --- a/drivers/scsi/libsas/sas_phy.c +++ b/drivers/scsi/libsas/sas_phy.c @@ -122,11 +122,10 @@ static void sas_phye_shutdown(struct work_struct *work) phy->enabled = 0; ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); if (ret) - pr_notice("lldd disable phy%02d returned %d\n", - phy->id, ret); + pr_notice("lldd disable phy%d returned %d\n", phy->id, + ret); } else - pr_notice("phy%02d is not enabled, cannot shutdown\n", - phy->id); + pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id); } /* ---------- Phy class registration ---------- */ diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 03fe479359b6..38a10478605c 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -95,6 +95,7 @@ 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 domain_device *port_dev; struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt); unsigned long flags; @@ -153,8 +154,9 @@ static void sas_form_port(struct asd_sas_phy *phy) } /* add the phy to the port */ + port_dev = port->port_dev; list_add_tail(&phy->port_phy_el, &port->phy_list); - sas_phy_set_target(phy, port->port_dev); + sas_phy_set_target(phy, port_dev); phy->port = port; port->num_phys++; port->phy_mask |= (1U << phy->id); @@ -184,14 +186,21 @@ static void sas_form_port(struct asd_sas_phy *phy) port->phy_mask, SAS_ADDR(port->attached_sas_addr)); - if (port->port_dev) - port->port_dev->pathways = port->num_phys; + if (port_dev) + 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); + /* Only insert a revalidate event after initial discovery */ + if (port_dev && sas_dev_type_is_expander(port_dev->dev_type)) { + struct expander_device *ex_dev = &port_dev->ex_dev; + + ex_dev->ex_change_count = -1; + sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); + } flush_workqueue(sas_ha->disco_q); } @@ -254,6 +263,15 @@ void sas_deform_port(struct asd_sas_phy *phy, int gone) spin_unlock(&port->phy_list_lock); spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); + /* Only insert revalidate event if the port still has members */ + if (port->port && dev && sas_dev_type_is_expander(dev->dev_type)) { + struct expander_device *ex_dev = &dev->ex_dev; + + ex_dev->ex_change_count = -1; + sas_discover_event(port, DISCE_REVALIDATE_DOMAIN); + } + flush_workqueue(sas_ha->disco_q); + return; } |