aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_expander.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2012-01-12 20:57:35 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-29 16:33:02 -0500
commit354cf82980e2449e71fdaa3c6f170357ebd65467 (patch)
tree8300579ebb51e19e503437d5c1f5ce2fd5186f18 /drivers/scsi/libsas/sas_expander.c
parenta692b0eec5efae382dfa800e8b4b083f172921a7 (diff)
[SCSI] libsas: let libata recover links that fail to transmit initial sig-fis
libsas fails to discover all sata devices in the domain. If a device fails negotiation and does not transmit a signature fis the link needs recovery. libata already understands how to manage slow to come up links, so treat these conditions as ata device attach events for the purposes of creating an ata_port. This allows libata to manage retrying link bring up. Rediscovery is modified to be careful about checking changes in dev_type. It looks like libsas leaks old devices if the sas address changes, but that's a fix for another patch. Acked-by: Jack Wang <jack_wang@usish.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas/sas_expander.c')
-rw-r--r--drivers/scsi/libsas/sas_expander.c178
1 files changed, 99 insertions, 79 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 4b2ecd35dc5a..7e2d3c4c6171 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -183,13 +183,27 @@ static char sas_route_char(struct domain_device *dev, struct ex_phy *phy)
183 } 183 }
184} 184}
185 185
186static void sas_set_ex_phy(struct domain_device *dev, int phy_id, 186static enum sas_dev_type to_dev_type(struct discover_resp *dr)
187 void *disc_resp)
188{ 187{
188 /* This is detecting a failure to transmit initial dev to host
189 * FIS as described in section J.5 of sas-2 r16
190 */
191 if (dr->attached_dev_type == NO_DEVICE && dr->attached_sata_dev &&
192 dr->linkrate >= SAS_LINK_RATE_1_5_GBPS)
193 return SATA_PENDING;
194 else
195 return dr->attached_dev_type;
196}
197
198static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
199{
200 enum sas_dev_type dev_type;
201 enum sas_linkrate linkrate;
202 u8 sas_addr[SAS_ADDR_SIZE];
203 struct smp_resp *resp = rsp;
204 struct discover_resp *dr = &resp->disc;
189 struct expander_device *ex = &dev->ex_dev; 205 struct expander_device *ex = &dev->ex_dev;
190 struct ex_phy *phy = &ex->ex_phy[phy_id]; 206 struct ex_phy *phy = &ex->ex_phy[phy_id];
191 struct smp_resp *resp = disc_resp;
192 struct discover_resp *dr = &resp->disc;
193 struct sas_rphy *rphy = dev->rphy; 207 struct sas_rphy *rphy = dev->rphy;
194 bool new_phy = !phy->phy; 208 bool new_phy = !phy->phy;
195 char *type; 209 char *type;
@@ -213,8 +227,13 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
213 break; 227 break;
214 } 228 }
215 229
230 /* check if anything important changed to squelch debug */
231 dev_type = phy->attached_dev_type;
232 linkrate = phy->linkrate;
233 memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
234
235 phy->attached_dev_type = to_dev_type(dr);
216 phy->phy_id = phy_id; 236 phy->phy_id = phy_id;
217 phy->attached_dev_type = dr->attached_dev_type;
218 phy->linkrate = dr->linkrate; 237 phy->linkrate = dr->linkrate;
219 phy->attached_sata_host = dr->attached_sata_host; 238 phy->attached_sata_host = dr->attached_sata_host;
220 phy->attached_sata_dev = dr->attached_sata_dev; 239 phy->attached_sata_dev = dr->attached_sata_dev;
@@ -229,7 +248,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
229 phy->last_da_index = -1; 248 phy->last_da_index = -1;
230 249
231 phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr); 250 phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
232 phy->phy->identify.device_type = phy->attached_dev_type; 251 phy->phy->identify.device_type = dr->attached_dev_type;
233 phy->phy->identify.initiator_port_protocols = phy->attached_iproto; 252 phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
234 phy->phy->identify.target_port_protocols = phy->attached_tproto; 253 phy->phy->identify.target_port_protocols = phy->attached_tproto;
235 phy->phy->identify.phy_identifier = phy_id; 254 phy->phy->identify.phy_identifier = phy_id;
@@ -246,6 +265,9 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
246 } 265 }
247 266
248 switch (phy->attached_dev_type) { 267 switch (phy->attached_dev_type) {
268 case SATA_PENDING:
269 type = "stp pending";
270 break;
249 case NO_DEVICE: 271 case NO_DEVICE:
250 type = "no device"; 272 type = "no device";
251 break; 273 break;
@@ -270,6 +292,16 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
270 type = "unknown"; 292 type = "unknown";
271 } 293 }
272 294
295 /* this routine is polled by libata error recovery so filter
296 * unimportant messages
297 */
298 if (new_phy || phy->attached_dev_type != dev_type ||
299 phy->linkrate != linkrate ||
300 SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr))
301 /* pass */;
302 else
303 return;
304
273 SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", 305 SAS_DPRINTK("ex %016llx phy%02d:%c:%X attached: %016llx (%s)\n",
274 SAS_ADDR(dev->sas_addr), phy->phy_id, 306 SAS_ADDR(dev->sas_addr), phy->phy_id,
275 sas_route_char(dev, phy), phy->linkrate, 307 sas_route_char(dev, phy), phy->linkrate,
@@ -304,50 +336,25 @@ struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
304static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, 336static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
305 u8 *disc_resp, int single) 337 u8 *disc_resp, int single)
306{ 338{
307 struct domain_device *ata_dev = sas_ex_to_ata(dev, single); 339 struct discover_resp *dr;
308 int i, res; 340 int res;
309 341
310 disc_req[9] = single; 342 disc_req[9] = single;
311 for (i = 1 ; i < 3; i++) {
312 struct discover_resp *dr;
313 343
314 res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE, 344 res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
315 disc_resp, DISCOVER_RESP_SIZE); 345 disc_resp, DISCOVER_RESP_SIZE);
316 if (res) 346 if (res)
317 return res; 347 return res;
318 dr = &((struct smp_resp *)disc_resp)->disc; 348 dr = &((struct smp_resp *)disc_resp)->disc;
319 if (memcmp(dev->sas_addr, dr->attached_sas_addr, 349 if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) {
320 SAS_ADDR_SIZE) == 0) { 350 sas_printk("Found loopback topology, just ignore it!\n");
321 sas_printk("Found loopback topology, just ignore it!\n"); 351 return 0;
322 return 0;
323 }
324
325 /* This is detecting a failure to transmit initial
326 * dev to host FIS as described in section J.5 of
327 * sas-2 r16
328 */
329 if (!(dr->attached_dev_type == 0 &&
330 dr->attached_sata_dev))
331 break;
332
333 /* In order to generate the dev to host FIS, we send a
334 * link reset to the expander port. If a device was
335 * previously detected on this port we ask libata to
336 * manage the reset and link recovery.
337 */
338 if (ata_dev) {
339 sas_ata_schedule_reset(ata_dev);
340 break;
341 }
342 sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
343 /* Wait for the reset to trigger the negotiation */
344 msleep(500);
345 } 352 }
346 sas_set_ex_phy(dev, single, disc_resp); 353 sas_set_ex_phy(dev, single, disc_resp);
347 return 0; 354 return 0;
348} 355}
349 356
350static int sas_ex_phy_discover(struct domain_device *dev, int single) 357int sas_ex_phy_discover(struct domain_device *dev, int single)
351{ 358{
352 struct expander_device *ex = &dev->ex_dev; 359 struct expander_device *ex = &dev->ex_dev;
353 int res = 0; 360 int res = 0;
@@ -652,9 +659,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy)
652#define RPS_REQ_SIZE 16 659#define RPS_REQ_SIZE 16
653#define RPS_RESP_SIZE 60 660#define RPS_RESP_SIZE 60
654 661
655static int sas_get_report_phy_sata(struct domain_device *dev, 662int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
656 int phy_id, 663 struct smp_resp *rps_resp)
657 struct smp_resp *rps_resp)
658{ 664{
659 int res; 665 int res;
660 u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); 666 u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
@@ -764,21 +770,9 @@ static struct domain_device *sas_ex_discover_end_dev(
764 770
765#ifdef CONFIG_SCSI_SAS_ATA 771#ifdef CONFIG_SCSI_SAS_ATA
766 if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { 772 if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
767 child->dev_type = SATA_DEV; 773 res = sas_get_ata_info(child, phy);
768 if (phy->attached_tproto & SAS_PROTOCOL_STP) 774 if (res)
769 child->tproto = phy->attached_tproto;
770 if (phy->attached_sata_dev)
771 child->tproto |= SATA_DEV;
772 res = sas_get_report_phy_sata(parent, phy_id,
773 &child->sata_dev.rps_resp);
774 if (res) {
775 SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
776 "0x%x\n", SAS_ADDR(parent->sas_addr),
777 phy_id, res);
778 goto out_free; 775 goto out_free;
779 }
780 memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
781 sizeof(struct dev_to_host_fis));
782 776
783 rphy = sas_end_device_alloc(phy->port); 777 rphy = sas_end_device_alloc(phy->port);
784 if (unlikely(!rphy)) 778 if (unlikely(!rphy))
@@ -993,7 +987,8 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
993 987
994 if (ex_phy->attached_dev_type != SAS_END_DEV && 988 if (ex_phy->attached_dev_type != SAS_END_DEV &&
995 ex_phy->attached_dev_type != FANOUT_DEV && 989 ex_phy->attached_dev_type != FANOUT_DEV &&
996 ex_phy->attached_dev_type != EDGE_DEV) { 990 ex_phy->attached_dev_type != EDGE_DEV &&
991 ex_phy->attached_dev_type != SATA_PENDING) {
997 SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx " 992 SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
998 "phy 0x%x\n", ex_phy->attached_dev_type, 993 "phy 0x%x\n", ex_phy->attached_dev_type,
999 SAS_ADDR(dev->sas_addr), 994 SAS_ADDR(dev->sas_addr),
@@ -1019,6 +1014,7 @@ static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
1019 1014
1020 switch (ex_phy->attached_dev_type) { 1015 switch (ex_phy->attached_dev_type) {
1021 case SAS_END_DEV: 1016 case SAS_END_DEV:
1017 case SATA_PENDING:
1022 child = sas_ex_discover_end_dev(dev, phy_id); 1018 child = sas_ex_discover_end_dev(dev, phy_id);
1023 break; 1019 break;
1024 case FANOUT_DEV: 1020 case FANOUT_DEV:
@@ -1688,8 +1684,8 @@ static int sas_get_phy_change_count(struct domain_device *dev,
1688 return res; 1684 return res;
1689} 1685}
1690 1686
1691int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id, 1687static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
1692 u8 *attached_sas_addr) 1688 u8 *sas_addr, enum sas_dev_type *type)
1693{ 1689{
1694 int res; 1690 int res;
1695 struct smp_resp *disc_resp; 1691 struct smp_resp *disc_resp;
@@ -1701,10 +1697,11 @@ int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
1701 dr = &disc_resp->disc; 1697 dr = &disc_resp->disc;
1702 1698
1703 res = sas_get_phy_discover(dev, phy_id, disc_resp); 1699 res = sas_get_phy_discover(dev, phy_id, disc_resp);
1704 if (!res) { 1700 if (res == 0) {
1705 memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8); 1701 memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8);
1706 if (dr->attached_dev_type == 0) 1702 *type = to_dev_type(dr);
1707 memset(attached_sas_addr, 0, 8); 1703 if (*type == 0)
1704 memset(sas_addr, 0, 8);
1708 } 1705 }
1709 kfree(disc_resp); 1706 kfree(disc_resp);
1710 return res; 1707 return res;
@@ -1953,39 +1950,62 @@ out:
1953 return res; 1950 return res;
1954} 1951}
1955 1952
1953static bool dev_type_flutter(enum sas_dev_type new, enum sas_dev_type old)
1954{
1955 if (old == new)
1956 return true;
1957
1958 /* treat device directed resets as flutter, if we went
1959 * SAS_END_DEV to SATA_PENDING the link needs recovery
1960 */
1961 if ((old == SATA_PENDING && new == SAS_END_DEV) ||
1962 (old == SAS_END_DEV && new == SATA_PENDING))
1963 return true;
1964
1965 return false;
1966}
1967
1956static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) 1968static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last)
1957{ 1969{
1958 struct expander_device *ex = &dev->ex_dev; 1970 struct expander_device *ex = &dev->ex_dev;
1959 struct ex_phy *phy = &ex->ex_phy[phy_id]; 1971 struct ex_phy *phy = &ex->ex_phy[phy_id];
1960 u8 attached_sas_addr[8]; 1972 enum sas_dev_type type = NO_DEVICE;
1973 u8 sas_addr[8];
1961 int res; 1974 int res;
1962 1975
1963 res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr); 1976 res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
1964 switch (res) { 1977 switch (res) {
1965 case SMP_RESP_NO_PHY: 1978 case SMP_RESP_NO_PHY:
1966 phy->phy_state = PHY_NOT_PRESENT; 1979 phy->phy_state = PHY_NOT_PRESENT;
1967 sas_unregister_devs_sas_addr(dev, phy_id, last); 1980 sas_unregister_devs_sas_addr(dev, phy_id, last);
1968 goto out; break; 1981 return res;
1969 case SMP_RESP_PHY_VACANT: 1982 case SMP_RESP_PHY_VACANT:
1970 phy->phy_state = PHY_VACANT; 1983 phy->phy_state = PHY_VACANT;
1971 sas_unregister_devs_sas_addr(dev, phy_id, last); 1984 sas_unregister_devs_sas_addr(dev, phy_id, last);
1972 goto out; break; 1985 return res;
1973 case SMP_RESP_FUNC_ACC: 1986 case SMP_RESP_FUNC_ACC:
1974 break; 1987 break;
1975 } 1988 }
1976 1989
1977 if (SAS_ADDR(attached_sas_addr) == 0) { 1990 if (SAS_ADDR(sas_addr) == 0) {
1978 phy->phy_state = PHY_EMPTY; 1991 phy->phy_state = PHY_EMPTY;
1979 sas_unregister_devs_sas_addr(dev, phy_id, last); 1992 sas_unregister_devs_sas_addr(dev, phy_id, last);
1980 } else if (SAS_ADDR(attached_sas_addr) == 1993 return res;
1981 SAS_ADDR(phy->attached_sas_addr)) { 1994 } else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
1982 SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n", 1995 dev_type_flutter(type, phy->attached_dev_type)) {
1983 SAS_ADDR(dev->sas_addr), phy_id); 1996 struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
1997 char *action = "";
1998
1984 sas_ex_phy_discover(dev, phy_id); 1999 sas_ex_phy_discover(dev, phy_id);
1985 } else 2000
1986 res = sas_discover_new(dev, phy_id); 2001 if (ata_dev && phy->attached_dev_type == SATA_PENDING)
1987out: 2002 action = ", needs recovery";
1988 return res; 2003 SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter%s\n",
2004 SAS_ADDR(dev->sas_addr), phy_id, action);
2005 return res;
2006 }
2007
2008 return sas_discover_new(dev, phy_id);
1989} 2009}
1990 2010
1991/** 2011/**