aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-10-27 18:05:37 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-10-31 05:23:01 -0400
commit52d74634335dfc0984ed955ed3c6ad6488495f96 (patch)
tree647120b0916abcc42f1e2d050f13175993509776 /drivers/scsi
parent8e35a1398c5db981cd1a2d7635de9c15dd648527 (diff)
[SCSI] isci: revert bcn filtering
The initial bcn filtering implementation was validated on a kernel baseline that predated the switch to new libata error handling. Also, prior to that conversion we borrowed the mvsas MVS_DEV_EH approach to prevent the unwanted extra ap->ops->phy_reset(ap) that occurred in the ata_bus_probe() path. After the conversion to new libata eh resets at discovery are more frequent and get filtered prematurely by IDEV_EH. The result is that our bcn filtering has been blocked from running and at discovery and it appears to stall discovery completion to the point of triggering hung task timeouts. So, revert the implementation for now. When it returns it will go into libsas proper. The domain rediscovery that takes place due to ->lldd_I_T_nexus_reset() events should now be properly waited for by the ata_port_wait_eh() call in ata_port_probe(). So the hard coded delay in the isci ->lldd_I_T_nexus_reset() and other libsas drivers should help debounce the libsas thread from seeing temporary device removals. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/isci/port.c45
-rw-r--r--drivers/scsi/isci/port.h5
-rw-r--r--drivers/scsi/isci/task.c235
3 files changed, 4 insertions, 281 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index bfeb87905aaf..ac7f27749f97 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -145,48 +145,15 @@ static void sci_port_bcn_enable(struct isci_port *iport)
145 } 145 }
146} 146}
147 147
148/* called under sci_lock to stabilize phy:port associations */
149void isci_port_bcn_enable(struct isci_host *ihost, struct isci_port *iport)
150{
151 int i;
152
153 clear_bit(IPORT_BCN_BLOCKED, &iport->flags);
154 wake_up(&ihost->eventq);
155
156 if (!test_and_clear_bit(IPORT_BCN_PENDING, &iport->flags))
157 return;
158
159 for (i = 0; i < ARRAY_SIZE(iport->phy_table); i++) {
160 struct isci_phy *iphy = iport->phy_table[i];
161
162 if (!iphy)
163 continue;
164
165 ihost->sas_ha.notify_port_event(&iphy->sas_phy,
166 PORTE_BROADCAST_RCVD);
167 break;
168 }
169}
170
171static void isci_port_bc_change_received(struct isci_host *ihost, 148static void isci_port_bc_change_received(struct isci_host *ihost,
172 struct isci_port *iport, 149 struct isci_port *iport,
173 struct isci_phy *iphy) 150 struct isci_phy *iphy)
174{ 151{
175 if (iport && test_bit(IPORT_BCN_BLOCKED, &iport->flags)) { 152 dev_dbg(&ihost->pdev->dev,
176 dev_dbg(&ihost->pdev->dev, 153 "%s: isci_phy = %p, sas_phy = %p\n",
177 "%s: disabled BCN; isci_phy = %p, sas_phy = %p\n", 154 __func__, iphy, &iphy->sas_phy);
178 __func__, iphy, &iphy->sas_phy);
179 set_bit(IPORT_BCN_PENDING, &iport->flags);
180 atomic_inc(&iport->event);
181 wake_up(&ihost->eventq);
182 } else {
183 dev_dbg(&ihost->pdev->dev,
184 "%s: isci_phy = %p, sas_phy = %p\n",
185 __func__, iphy, &iphy->sas_phy);
186 155
187 ihost->sas_ha.notify_port_event(&iphy->sas_phy, 156 ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD);
188 PORTE_BROADCAST_RCVD);
189 }
190 sci_port_bcn_enable(iport); 157 sci_port_bcn_enable(iport);
191} 158}
192 159
@@ -278,9 +245,6 @@ static void isci_port_link_down(struct isci_host *isci_host,
278 /* check to see if this is the last phy on this port. */ 245 /* check to see if this is the last phy on this port. */
279 if (isci_phy->sas_phy.port && 246 if (isci_phy->sas_phy.port &&
280 isci_phy->sas_phy.port->num_phys == 1) { 247 isci_phy->sas_phy.port->num_phys == 1) {
281 atomic_inc(&isci_port->event);
282 isci_port_bcn_enable(isci_host, isci_port);
283
284 /* change the state for all devices on this port. The 248 /* change the state for all devices on this port. The
285 * next task sent to this device will be returned as 249 * next task sent to this device will be returned as
286 * SAS_TASK_UNDELIVERED, and the scsi mid layer will 250 * SAS_TASK_UNDELIVERED, and the scsi mid layer will
@@ -1672,7 +1636,6 @@ void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index)
1672 init_completion(&iport->start_complete); 1636 init_completion(&iport->start_complete);
1673 iport->isci_host = ihost; 1637 iport->isci_host = ihost;
1674 isci_port_change_state(iport, isci_freed); 1638 isci_port_change_state(iport, isci_freed);
1675 atomic_set(&iport->event, 0);
1676} 1639}
1677 1640
1678/** 1641/**
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h
index e84d22a309e3..cb5ffbc38603 100644
--- a/drivers/scsi/isci/port.h
+++ b/drivers/scsi/isci/port.h
@@ -77,7 +77,6 @@ enum isci_status {
77 77
78/** 78/**
79 * struct isci_port - isci direct attached sas port object 79 * struct isci_port - isci direct attached sas port object
80 * @event: counts bcns and port stop events (for bcn filtering)
81 * @ready_exit: several states constitute 'ready'. When exiting ready we 80 * @ready_exit: several states constitute 'ready'. When exiting ready we
82 * need to take extra port-teardown actions that are 81 * need to take extra port-teardown actions that are
83 * skipped when exiting to another 'ready' state. 82 * skipped when exiting to another 'ready' state.
@@ -92,10 +91,6 @@ enum isci_status {
92 */ 91 */
93struct isci_port { 92struct isci_port {
94 enum isci_status status; 93 enum isci_status status;
95 #define IPORT_BCN_BLOCKED 0
96 #define IPORT_BCN_PENDING 1
97 unsigned long flags;
98 atomic_t event;
99 struct isci_host *isci_host; 94 struct isci_host *isci_host;
100 struct asd_sas_port sas_port; 95 struct asd_sas_port sas_port;
101 struct list_head remote_dev_list; 96 struct list_head remote_dev_list;
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 6d8ff15a03d1..66ad3dc89498 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -1331,226 +1331,10 @@ isci_task_request_complete(struct isci_host *ihost,
1331 complete(tmf_complete); 1331 complete(tmf_complete);
1332} 1332}
1333 1333
1334static void isci_smp_task_timedout(unsigned long _task)
1335{
1336 struct sas_task *task = (void *) _task;
1337 unsigned long flags;
1338
1339 spin_lock_irqsave(&task->task_state_lock, flags);
1340 if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
1341 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
1342 spin_unlock_irqrestore(&task->task_state_lock, flags);
1343
1344 complete(&task->completion);
1345}
1346
1347static void isci_smp_task_done(struct sas_task *task)
1348{
1349 if (!del_timer(&task->timer))
1350 return;
1351 complete(&task->completion);
1352}
1353
1354static int isci_smp_execute_task(struct isci_host *ihost,
1355 struct domain_device *dev, void *req,
1356 int req_size, void *resp, int resp_size)
1357{
1358 int res, retry;
1359 struct sas_task *task = NULL;
1360
1361 for (retry = 0; retry < 3; retry++) {
1362 task = sas_alloc_task(GFP_KERNEL);
1363 if (!task)
1364 return -ENOMEM;
1365
1366 task->dev = dev;
1367 task->task_proto = dev->tproto;
1368 sg_init_one(&task->smp_task.smp_req, req, req_size);
1369 sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
1370
1371 task->task_done = isci_smp_task_done;
1372
1373 task->timer.data = (unsigned long) task;
1374 task->timer.function = isci_smp_task_timedout;
1375 task->timer.expires = jiffies + 10*HZ;
1376 add_timer(&task->timer);
1377
1378 res = isci_task_execute_task(task, 1, GFP_KERNEL);
1379
1380 if (res) {
1381 del_timer(&task->timer);
1382 dev_dbg(&ihost->pdev->dev,
1383 "%s: executing SMP task failed:%d\n",
1384 __func__, res);
1385 goto ex_err;
1386 }
1387
1388 wait_for_completion(&task->completion);
1389 res = -ECOMM;
1390 if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
1391 dev_dbg(&ihost->pdev->dev,
1392 "%s: smp task timed out or aborted\n",
1393 __func__);
1394 isci_task_abort_task(task);
1395 if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
1396 dev_dbg(&ihost->pdev->dev,
1397 "%s: SMP task aborted and not done\n",
1398 __func__);
1399 goto ex_err;
1400 }
1401 }
1402 if (task->task_status.resp == SAS_TASK_COMPLETE &&
1403 task->task_status.stat == SAM_STAT_GOOD) {
1404 res = 0;
1405 break;
1406 }
1407 if (task->task_status.resp == SAS_TASK_COMPLETE &&
1408 task->task_status.stat == SAS_DATA_UNDERRUN) {
1409 /* no error, but return the number of bytes of
1410 * underrun */
1411 res = task->task_status.residual;
1412 break;
1413 }
1414 if (task->task_status.resp == SAS_TASK_COMPLETE &&
1415 task->task_status.stat == SAS_DATA_OVERRUN) {
1416 res = -EMSGSIZE;
1417 break;
1418 } else {
1419 dev_dbg(&ihost->pdev->dev,
1420 "%s: task to dev %016llx response: 0x%x "
1421 "status 0x%x\n", __func__,
1422 SAS_ADDR(dev->sas_addr),
1423 task->task_status.resp,
1424 task->task_status.stat);
1425 sas_free_task(task);
1426 task = NULL;
1427 }
1428 }
1429ex_err:
1430 BUG_ON(retry == 3 && task != NULL);
1431 sas_free_task(task);
1432 return res;
1433}
1434
1435#define DISCOVER_REQ_SIZE 16
1436#define DISCOVER_RESP_SIZE 56
1437
1438int isci_smp_get_phy_attached_dev_type(struct isci_host *ihost,
1439 struct domain_device *dev,
1440 int phy_id, int *adt)
1441{
1442 struct smp_resp *disc_resp;
1443 u8 *disc_req;
1444 int res;
1445
1446 disc_resp = kzalloc(DISCOVER_RESP_SIZE, GFP_KERNEL);
1447 if (!disc_resp)
1448 return -ENOMEM;
1449
1450 disc_req = kzalloc(DISCOVER_REQ_SIZE, GFP_KERNEL);
1451 if (disc_req) {
1452 disc_req[0] = SMP_REQUEST;
1453 disc_req[1] = SMP_DISCOVER;
1454 disc_req[9] = phy_id;
1455 } else {
1456 kfree(disc_resp);
1457 return -ENOMEM;
1458 }
1459 res = isci_smp_execute_task(ihost, dev, disc_req, DISCOVER_REQ_SIZE,
1460 disc_resp, DISCOVER_RESP_SIZE);
1461 if (!res) {
1462 if (disc_resp->result != SMP_RESP_FUNC_ACC)
1463 res = disc_resp->result;
1464 else
1465 *adt = disc_resp->disc.attached_dev_type;
1466 }
1467 kfree(disc_req);
1468 kfree(disc_resp);
1469
1470 return res;
1471}
1472
1473static void isci_wait_for_smp_phy_reset(struct isci_remote_device *idev, int phy_num)
1474{
1475 struct domain_device *dev = idev->domain_dev;
1476 struct isci_port *iport = idev->isci_port;
1477 struct isci_host *ihost = iport->isci_host;
1478 int res, iteration = 0, attached_device_type;
1479 #define STP_WAIT_MSECS 25000
1480 unsigned long tmo = msecs_to_jiffies(STP_WAIT_MSECS);
1481 unsigned long deadline = jiffies + tmo;
1482 enum {
1483 SMP_PHYWAIT_PHYDOWN,
1484 SMP_PHYWAIT_PHYUP,
1485 SMP_PHYWAIT_DONE
1486 } phy_state = SMP_PHYWAIT_PHYDOWN;
1487
1488 /* While there is time, wait for the phy to go away and come back */
1489 while (time_is_after_jiffies(deadline) && phy_state != SMP_PHYWAIT_DONE) {
1490 int event = atomic_read(&iport->event);
1491
1492 ++iteration;
1493
1494 tmo = wait_event_timeout(ihost->eventq,
1495 event != atomic_read(&iport->event) ||
1496 !test_bit(IPORT_BCN_BLOCKED, &iport->flags),
1497 tmo);
1498 /* link down, stop polling */
1499 if (!test_bit(IPORT_BCN_BLOCKED, &iport->flags))
1500 break;
1501
1502 dev_dbg(&ihost->pdev->dev,
1503 "%s: iport %p, iteration %d,"
1504 " phase %d: time_remaining %lu, bcns = %d\n",
1505 __func__, iport, iteration, phy_state,
1506 tmo, test_bit(IPORT_BCN_PENDING, &iport->flags));
1507
1508 res = isci_smp_get_phy_attached_dev_type(ihost, dev, phy_num,
1509 &attached_device_type);
1510 tmo = deadline - jiffies;
1511
1512 if (res) {
1513 dev_dbg(&ihost->pdev->dev,
1514 "%s: iteration %d, phase %d:"
1515 " SMP error=%d, time_remaining=%lu\n",
1516 __func__, iteration, phy_state, res, tmo);
1517 break;
1518 }
1519 dev_dbg(&ihost->pdev->dev,
1520 "%s: iport %p, iteration %d,"
1521 " phase %d: time_remaining %lu, bcns = %d, "
1522 "attdevtype = %x\n",
1523 __func__, iport, iteration, phy_state,
1524 tmo, test_bit(IPORT_BCN_PENDING, &iport->flags),
1525 attached_device_type);
1526
1527 switch (phy_state) {
1528 case SMP_PHYWAIT_PHYDOWN:
1529 /* Has the device gone away? */
1530 if (!attached_device_type)
1531 phy_state = SMP_PHYWAIT_PHYUP;
1532
1533 break;
1534
1535 case SMP_PHYWAIT_PHYUP:
1536 /* Has the device come back? */
1537 if (attached_device_type)
1538 phy_state = SMP_PHYWAIT_DONE;
1539 break;
1540
1541 case SMP_PHYWAIT_DONE:
1542 break;
1543 }
1544
1545 }
1546 dev_dbg(&ihost->pdev->dev, "%s: done\n", __func__);
1547}
1548
1549static int isci_reset_device(struct isci_host *ihost, 1334static int isci_reset_device(struct isci_host *ihost,
1550 struct isci_remote_device *idev) 1335 struct isci_remote_device *idev)
1551{ 1336{
1552 struct sas_phy *phy = sas_find_local_phy(idev->domain_dev); 1337 struct sas_phy *phy = sas_find_local_phy(idev->domain_dev);
1553 struct isci_port *iport = idev->isci_port;
1554 enum sci_status status; 1338 enum sci_status status;
1555 unsigned long flags; 1339 unsigned long flags;
1556 int rc; 1340 int rc;
@@ -1570,10 +1354,6 @@ static int isci_reset_device(struct isci_host *ihost,
1570 } 1354 }
1571 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1355 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1572 1356
1573 /* If this is a device on an expander, disable BCN processing. */
1574 if (!scsi_is_sas_phy_local(phy))
1575 set_bit(IPORT_BCN_BLOCKED, &iport->flags);
1576
1577 rc = sas_phy_reset(phy, true); 1357 rc = sas_phy_reset(phy, true);
1578 1358
1579 /* Terminate in-progress I/O now. */ 1359 /* Terminate in-progress I/O now. */
@@ -1584,21 +1364,6 @@ static int isci_reset_device(struct isci_host *ihost,
1584 status = sci_remote_device_reset_complete(idev); 1364 status = sci_remote_device_reset_complete(idev);
1585 spin_unlock_irqrestore(&ihost->scic_lock, flags); 1365 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1586 1366
1587 /* If this is a device on an expander, bring the phy back up. */
1588 if (!scsi_is_sas_phy_local(phy)) {
1589 /* A phy reset will cause the device to go away then reappear.
1590 * Since libsas will take action on incoming BCNs (eg. remove
1591 * a device going through an SMP phy-control driven reset),
1592 * we need to wait until the phy comes back up before letting
1593 * discovery proceed in libsas.
1594 */
1595 isci_wait_for_smp_phy_reset(idev, phy->number);
1596
1597 spin_lock_irqsave(&ihost->scic_lock, flags);
1598 isci_port_bcn_enable(ihost, idev->isci_port);
1599 spin_unlock_irqrestore(&ihost->scic_lock, flags);
1600 }
1601
1602 if (status != SCI_SUCCESS) { 1367 if (status != SCI_SUCCESS) {
1603 dev_dbg(&ihost->pdev->dev, 1368 dev_dbg(&ihost->pdev->dev,
1604 "%s: sci_remote_device_reset_complete(%p) " 1369 "%s: sci_remote_device_reset_complete(%p) "