aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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) "