diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/scsi/isci/port.c | 45 | ||||
| -rw-r--r-- | drivers/scsi/isci/port.h | 5 | ||||
| -rw-r--r-- | drivers/scsi/isci/task.c | 235 |
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 */ | ||
| 149 | void 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 | |||
| 171 | static void isci_port_bc_change_received(struct isci_host *ihost, | 148 | static 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 | */ |
| 93 | struct isci_port { | 92 | struct 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 | ||
| 1334 | static 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 | |||
| 1347 | static void isci_smp_task_done(struct sas_task *task) | ||
| 1348 | { | ||
| 1349 | if (!del_timer(&task->timer)) | ||
| 1350 | return; | ||
| 1351 | complete(&task->completion); | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | static 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 | } | ||
| 1429 | ex_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 | |||
| 1438 | int 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 | |||
| 1473 | static 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 | |||
| 1549 | static int isci_reset_device(struct isci_host *ihost, | 1334 | static 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) " |
