aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libsas/sas_expander.c81
1 files changed, 68 insertions, 13 deletions
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 23e90c5f8f35..0c4e3a977915 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -220,6 +220,36 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
220#define DISCOVER_REQ_SIZE 16 220#define DISCOVER_REQ_SIZE 16
221#define DISCOVER_RESP_SIZE 56 221#define DISCOVER_RESP_SIZE 56
222 222
223static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
224 u8 *disc_resp, int single)
225{
226 int i, res;
227
228 disc_req[9] = single;
229 for (i = 1 ; i < 3; i++) {
230 struct discover_resp *dr;
231
232 res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
233 disc_resp, DISCOVER_RESP_SIZE);
234 if (res)
235 return res;
236 /* This is detecting a failure to transmit inital
237 * dev to host FIS as described in section G.5 of
238 * sas-2 r 04b */
239 dr = &((struct smp_resp *)disc_resp)->disc;
240 if (!(dr->attached_dev_type == 0 &&
241 dr->attached_sata_dev))
242 break;
243 /* In order to generate the dev to host FIS, we
244 * send a link reset to the expander port */
245 sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET);
246 /* Wait for the reset to trigger the negotiation */
247 msleep(500);
248 }
249 sas_set_ex_phy(dev, single, disc_resp);
250 return 0;
251}
252
223static int sas_ex_phy_discover(struct domain_device *dev, int single) 253static int sas_ex_phy_discover(struct domain_device *dev, int single)
224{ 254{
225 struct expander_device *ex = &dev->ex_dev; 255 struct expander_device *ex = &dev->ex_dev;
@@ -240,23 +270,15 @@ static int sas_ex_phy_discover(struct domain_device *dev, int single)
240 disc_req[1] = SMP_DISCOVER; 270 disc_req[1] = SMP_DISCOVER;
241 271
242 if (0 <= single && single < ex->num_phys) { 272 if (0 <= single && single < ex->num_phys) {
243 disc_req[9] = single; 273 res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single);
244 res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
245 disc_resp, DISCOVER_RESP_SIZE);
246 if (res)
247 goto out_err;
248 sas_set_ex_phy(dev, single, disc_resp);
249 } else { 274 } else {
250 int i; 275 int i;
251 276
252 for (i = 0; i < ex->num_phys; i++) { 277 for (i = 0; i < ex->num_phys; i++) {
253 disc_req[9] = i; 278 res = sas_ex_phy_discover_helper(dev, disc_req,
254 res = smp_execute_task(dev, disc_req, 279 disc_resp, i);
255 DISCOVER_REQ_SIZE, disc_resp,
256 DISCOVER_RESP_SIZE);
257 if (res) 280 if (res)
258 goto out_err; 281 goto out_err;
259 sas_set_ex_phy(dev, i, disc_resp);
260 } 282 }
261 } 283 }
262out_err: 284out_err:
@@ -529,6 +551,7 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
529{ 551{
530 int res; 552 int res;
531 u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); 553 u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
554 u8 *resp = (u8 *)rps_resp;
532 555
533 if (!rps_req) 556 if (!rps_req)
534 return -ENOMEM; 557 return -ENOMEM;
@@ -539,8 +562,28 @@ static int sas_get_report_phy_sata(struct domain_device *dev,
539 res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE, 562 res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
540 rps_resp, RPS_RESP_SIZE); 563 rps_resp, RPS_RESP_SIZE);
541 564
565 /* 0x34 is the FIS type for the D2H fis. There's a potential
566 * standards cockup here. sas-2 explicitly specifies the FIS
567 * should be encoded so that FIS type is in resp[24].
568 * However, some expanders endian reverse this. Undo the
569 * reversal here */
570 if (!res && resp[27] == 0x34 && resp[24] != 0x34) {
571 int i;
572
573 for (i = 0; i < 5; i++) {
574 int j = 24 + (i*4);
575 u8 a, b;
576 a = resp[j + 0];
577 b = resp[j + 1];
578 resp[j + 0] = resp[j + 3];
579 resp[j + 1] = resp[j + 2];
580 resp[j + 2] = b;
581 resp[j + 3] = a;
582 }
583 }
584
542 kfree(rps_req); 585 kfree(rps_req);
543 return 0; 586 return res;
544} 587}
545 588
546static void sas_ex_get_linkrate(struct domain_device *parent, 589static void sas_ex_get_linkrate(struct domain_device *parent,
@@ -625,14 +668,26 @@ static struct domain_device *sas_ex_discover_end_dev(
625 } 668 }
626 memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, 669 memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
627 sizeof(struct dev_to_host_fis)); 670 sizeof(struct dev_to_host_fis));
671
672 rphy = sas_end_device_alloc(phy->port);
673 /* FIXME: error handling */
674 BUG_ON(!rphy);
675
628 sas_init_dev(child); 676 sas_init_dev(child);
677
678 child->rphy = rphy;
679
680 spin_lock(&parent->port->dev_list_lock);
681 list_add_tail(&child->dev_list_node, &parent->port->dev_list);
682 spin_unlock(&parent->port->dev_list_lock);
683
629 res = sas_discover_sata(child); 684 res = sas_discover_sata(child);
630 if (res) { 685 if (res) {
631 SAS_DPRINTK("sas_discover_sata() for device %16llx at " 686 SAS_DPRINTK("sas_discover_sata() for device %16llx at "
632 "%016llx:0x%x returned 0x%x\n", 687 "%016llx:0x%x returned 0x%x\n",
633 SAS_ADDR(child->sas_addr), 688 SAS_ADDR(child->sas_addr),
634 SAS_ADDR(parent->sas_addr), phy_id, res); 689 SAS_ADDR(parent->sas_addr), phy_id, res);
635 goto out_free; 690 goto out_list_del;
636 } 691 }
637 } else if (phy->attached_tproto & SAS_PROTO_SSP) { 692 } else if (phy->attached_tproto & SAS_PROTO_SSP) {
638 child->dev_type = SAS_END_DEV; 693 child->dev_type = SAS_END_DEV;