diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 241 |
1 files changed, 213 insertions, 28 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 5a06d8d8694e..2512d0e6155e 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -89,6 +89,8 @@ static int mptsasMgmtCtx = -1; | |||
89 | enum mptsas_hotplug_action { | 89 | enum mptsas_hotplug_action { |
90 | MPTSAS_ADD_DEVICE, | 90 | MPTSAS_ADD_DEVICE, |
91 | MPTSAS_DEL_DEVICE, | 91 | MPTSAS_DEL_DEVICE, |
92 | MPTSAS_ADD_RAID, | ||
93 | MPTSAS_DEL_RAID, | ||
92 | }; | 94 | }; |
93 | 95 | ||
94 | struct mptsas_hotplug_event { | 96 | struct mptsas_hotplug_event { |
@@ -114,6 +116,7 @@ struct mptsas_hotplug_event { | |||
114 | 116 | ||
115 | struct mptsas_devinfo { | 117 | struct mptsas_devinfo { |
116 | u16 handle; /* unique id to address this device */ | 118 | u16 handle; /* unique id to address this device */ |
119 | u16 handle_parent; /* unique id to address parent device */ | ||
117 | u8 phy_id; /* phy number of parent device */ | 120 | u8 phy_id; /* phy number of parent device */ |
118 | u8 port_id; /* sas physical port this device | 121 | u8 port_id; /* sas physical port this device |
119 | is assoc'd with */ | 122 | is assoc'd with */ |
@@ -301,9 +304,8 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
301 | } | 304 | } |
302 | mutex_unlock(&hd->ioc->sas_topology_mutex); | 305 | mutex_unlock(&hd->ioc->sas_topology_mutex); |
303 | 306 | ||
304 | printk("No matching SAS device found!!\n"); | ||
305 | kfree(vdev); | 307 | kfree(vdev); |
306 | return -ENODEV; | 308 | return -ENXIO; |
307 | 309 | ||
308 | out: | 310 | out: |
309 | vtarget->ioc_id = vdev->ioc_id; | 311 | vtarget->ioc_id = vdev->ioc_id; |
@@ -321,6 +323,7 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
321 | struct sas_rphy *rphy; | 323 | struct sas_rphy *rphy; |
322 | struct mptsas_portinfo *p; | 324 | struct mptsas_portinfo *p; |
323 | int i; | 325 | int i; |
326 | VirtDevice *vdev; | ||
324 | 327 | ||
325 | /* | 328 | /* |
326 | * Handle hotplug removal case. | 329 | * Handle hotplug removal case. |
@@ -344,8 +347,29 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
344 | out: | 347 | out: |
345 | mutex_unlock(&hd->ioc->sas_topology_mutex); | 348 | mutex_unlock(&hd->ioc->sas_topology_mutex); |
346 | /* | 349 | /* |
347 | * TODO: Issue target reset to flush firmware outstanding commands. | 350 | * Issue target reset to flush firmware outstanding commands. |
348 | */ | 351 | */ |
352 | vdev = sdev->hostdata; | ||
353 | if (vdev->configured_lun){ | ||
354 | if (mptscsih_TMHandler(hd, | ||
355 | MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, | ||
356 | vdev->bus_id, | ||
357 | vdev->target_id, | ||
358 | 0, 0, 5 /* 5 second timeout */) | ||
359 | < 0){ | ||
360 | |||
361 | /* The TM request failed! | ||
362 | * Fatal error case. | ||
363 | */ | ||
364 | printk(MYIOC_s_WARN_FMT | ||
365 | "Error processing TaskMgmt id=%d TARGET_RESET\n", | ||
366 | hd->ioc->name, | ||
367 | vdev->target_id); | ||
368 | |||
369 | hd->tmPending = 0; | ||
370 | hd->tmState = TM_STATE_NONE; | ||
371 | } | ||
372 | } | ||
349 | mptscsih_slave_destroy(sdev); | 373 | mptscsih_slave_destroy(sdev); |
350 | } | 374 | } |
351 | 375 | ||
@@ -714,6 +738,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
714 | mptsas_print_device_pg0(buffer); | 738 | mptsas_print_device_pg0(buffer); |
715 | 739 | ||
716 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 740 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
741 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | ||
717 | device_info->phy_id = buffer->PhyNum; | 742 | device_info->phy_id = buffer->PhyNum; |
718 | device_info->port_id = buffer->PhysicalPort; | 743 | device_info->port_id = buffer->PhysicalPort; |
719 | device_info->id = buffer->TargetID; | 744 | device_info->id = buffer->TargetID; |
@@ -863,6 +888,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
863 | return error; | 888 | return error; |
864 | } | 889 | } |
865 | 890 | ||
891 | /* | ||
892 | * Returns true if there is a scsi end device | ||
893 | */ | ||
894 | static inline int | ||
895 | mptsas_is_end_device(struct mptsas_devinfo * attached) | ||
896 | { | ||
897 | if ((attached->handle) && | ||
898 | (attached->device_info & | ||
899 | MPI_SAS_DEVICE_INFO_END_DEVICE) && | ||
900 | ((attached->device_info & | ||
901 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | | ||
902 | (attached->device_info & | ||
903 | MPI_SAS_DEVICE_INFO_STP_TARGET) | | ||
904 | (attached->device_info & | ||
905 | MPI_SAS_DEVICE_INFO_SATA_DEVICE))) | ||
906 | return 1; | ||
907 | else | ||
908 | return 0; | ||
909 | } | ||
910 | |||
866 | static void | 911 | static void |
867 | mptsas_parse_device_info(struct sas_identify *identify, | 912 | mptsas_parse_device_info(struct sas_identify *identify, |
868 | struct mptsas_devinfo *device_info) | 913 | struct mptsas_devinfo *device_info) |
@@ -1227,7 +1272,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | |||
1227 | } | 1272 | } |
1228 | 1273 | ||
1229 | static struct mptsas_phyinfo * | 1274 | static struct mptsas_phyinfo * |
1230 | mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | 1275 | mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) |
1231 | { | 1276 | { |
1232 | struct mptsas_portinfo *port_info; | 1277 | struct mptsas_portinfo *port_info; |
1233 | struct mptsas_phyinfo *phy_info = NULL; | 1278 | struct mptsas_phyinfo *phy_info = NULL; |
@@ -1239,12 +1284,12 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | |||
1239 | */ | 1284 | */ |
1240 | mutex_lock(&ioc->sas_topology_mutex); | 1285 | mutex_lock(&ioc->sas_topology_mutex); |
1241 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | 1286 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
1242 | for (i = 0; i < port_info->num_phys; i++) { | 1287 | for (i = 0; i < port_info->num_phys; i++) |
1243 | if (port_info->phy_info[i].attached.handle == handle) { | 1288 | if (mptsas_is_end_device(&port_info->phy_info[i].attached)) |
1244 | phy_info = &port_info->phy_info[i]; | 1289 | if (port_info->phy_info[i].attached.id == id) { |
1245 | break; | 1290 | phy_info = &port_info->phy_info[i]; |
1246 | } | 1291 | break; |
1247 | } | 1292 | } |
1248 | } | 1293 | } |
1249 | mutex_unlock(&ioc->sas_topology_mutex); | 1294 | mutex_unlock(&ioc->sas_topology_mutex); |
1250 | 1295 | ||
@@ -1258,36 +1303,58 @@ mptsas_hotplug_work(void *arg) | |||
1258 | MPT_ADAPTER *ioc = ev->ioc; | 1303 | MPT_ADAPTER *ioc = ev->ioc; |
1259 | struct mptsas_phyinfo *phy_info; | 1304 | struct mptsas_phyinfo *phy_info; |
1260 | struct sas_rphy *rphy; | 1305 | struct sas_rphy *rphy; |
1306 | struct scsi_device *sdev; | ||
1261 | char *ds = NULL; | 1307 | char *ds = NULL; |
1262 | 1308 | struct mptsas_devinfo sas_device; | |
1263 | if (ev->device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1264 | ds = "ssp"; | ||
1265 | if (ev->device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1266 | ds = "stp"; | ||
1267 | if (ev->device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1268 | ds = "sata"; | ||
1269 | 1309 | ||
1270 | switch (ev->event_type) { | 1310 | switch (ev->event_type) { |
1271 | case MPTSAS_DEL_DEVICE: | 1311 | case MPTSAS_DEL_DEVICE: |
1272 | printk(MYIOC_s_INFO_FMT | ||
1273 | "removing %s device, channel %d, id %d, phy %d\n", | ||
1274 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
1275 | 1312 | ||
1276 | phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle); | 1313 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); |
1277 | if (!phy_info) { | 1314 | if (!phy_info) { |
1278 | printk("mptsas: remove event for non-existant PHY.\n"); | 1315 | printk("mptsas: remove event for non-existant PHY.\n"); |
1279 | break; | 1316 | break; |
1280 | } | 1317 | } |
1281 | 1318 | ||
1319 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1320 | ds = "ssp"; | ||
1321 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1322 | ds = "stp"; | ||
1323 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1324 | ds = "sata"; | ||
1325 | |||
1326 | printk(MYIOC_s_INFO_FMT | ||
1327 | "removing %s device, channel %d, id %d, phy %d\n", | ||
1328 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | ||
1329 | |||
1282 | if (phy_info->rphy) { | 1330 | if (phy_info->rphy) { |
1283 | sas_rphy_delete(phy_info->rphy); | 1331 | sas_rphy_delete(phy_info->rphy); |
1284 | phy_info->rphy = NULL; | 1332 | phy_info->rphy = NULL; |
1285 | } | 1333 | } |
1286 | break; | 1334 | break; |
1287 | case MPTSAS_ADD_DEVICE: | 1335 | case MPTSAS_ADD_DEVICE: |
1288 | printk(MYIOC_s_INFO_FMT | 1336 | |
1289 | "attaching %s device, channel %d, id %d, phy %d\n", | 1337 | /* |
1290 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | 1338 | * When there is no sas address, |
1339 | * RAID volumes are being deleted, | ||
1340 | * and hidden phy disk are being added. | ||
1341 | * We don't know the SAS data yet, | ||
1342 | * so lookup sas device page to get | ||
1343 | * pertaining info | ||
1344 | */ | ||
1345 | if (!ev->sas_address) { | ||
1346 | if (mptsas_sas_device_pg0(ioc, | ||
1347 | &sas_device, ev->id, | ||
1348 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
1349 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT))) | ||
1350 | break; | ||
1351 | ev->handle = sas_device.handle; | ||
1352 | ev->parent_handle = sas_device.handle_parent; | ||
1353 | ev->channel = sas_device.channel; | ||
1354 | ev->phy_id = sas_device.phy_id; | ||
1355 | ev->sas_address = sas_device.sas_address; | ||
1356 | ev->device_info = sas_device.device_info; | ||
1357 | } | ||
1291 | 1358 | ||
1292 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1359 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
1293 | ev->parent_handle, ev->phy_id); | 1360 | ev->parent_handle, ev->phy_id); |
@@ -1310,10 +1377,23 @@ mptsas_hotplug_work(void *arg) | |||
1310 | phy_info->attached.sas_address = ev->sas_address; | 1377 | phy_info->attached.sas_address = ev->sas_address; |
1311 | phy_info->attached.device_info = ev->device_info; | 1378 | phy_info->attached.device_info = ev->device_info; |
1312 | 1379 | ||
1380 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1381 | ds = "ssp"; | ||
1382 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1383 | ds = "stp"; | ||
1384 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1385 | ds = "sata"; | ||
1386 | |||
1387 | printk(MYIOC_s_INFO_FMT | ||
1388 | "attaching %s device, channel %d, id %d, phy %d\n", | ||
1389 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
1390 | |||
1391 | |||
1313 | rphy = sas_rphy_alloc(phy_info->phy); | 1392 | rphy = sas_rphy_alloc(phy_info->phy); |
1314 | if (!rphy) | 1393 | if (!rphy) |
1315 | break; /* non-fatal: an rphy can be added later */ | 1394 | break; /* non-fatal: an rphy can be added later */ |
1316 | 1395 | ||
1396 | rphy->scsi_target_id = phy_info->attached.id; | ||
1317 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | 1397 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); |
1318 | if (sas_rphy_add(rphy)) { | 1398 | if (sas_rphy_add(rphy)) { |
1319 | sas_rphy_free(rphy); | 1399 | sas_rphy_free(rphy); |
@@ -1322,6 +1402,40 @@ mptsas_hotplug_work(void *arg) | |||
1322 | 1402 | ||
1323 | phy_info->rphy = rphy; | 1403 | phy_info->rphy = rphy; |
1324 | break; | 1404 | break; |
1405 | case MPTSAS_ADD_RAID: | ||
1406 | sdev = scsi_device_lookup( | ||
1407 | ioc->sh, | ||
1408 | ioc->num_ports, | ||
1409 | ev->id, | ||
1410 | 0); | ||
1411 | if (sdev) { | ||
1412 | scsi_device_put(sdev); | ||
1413 | break; | ||
1414 | } | ||
1415 | printk(MYIOC_s_INFO_FMT | ||
1416 | "attaching device, channel %d, id %d\n", | ||
1417 | ioc->name, ioc->num_ports, ev->id); | ||
1418 | scsi_add_device(ioc->sh, | ||
1419 | ioc->num_ports, | ||
1420 | ev->id, | ||
1421 | 0); | ||
1422 | mpt_findImVolumes(ioc); | ||
1423 | break; | ||
1424 | case MPTSAS_DEL_RAID: | ||
1425 | sdev = scsi_device_lookup( | ||
1426 | ioc->sh, | ||
1427 | ioc->num_ports, | ||
1428 | ev->id, | ||
1429 | 0); | ||
1430 | if (!sdev) | ||
1431 | break; | ||
1432 | printk(MYIOC_s_INFO_FMT | ||
1433 | "removing device, channel %d, id %d\n", | ||
1434 | ioc->name, ioc->num_ports, ev->id); | ||
1435 | scsi_remove_device(sdev); | ||
1436 | scsi_device_put(sdev); | ||
1437 | mpt_findImVolumes(ioc); | ||
1438 | break; | ||
1325 | } | 1439 | } |
1326 | 1440 | ||
1327 | kfree(ev); | 1441 | kfree(ev); |
@@ -1372,23 +1486,94 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, | |||
1372 | schedule_work(&ev->work); | 1486 | schedule_work(&ev->work); |
1373 | } | 1487 | } |
1374 | 1488 | ||
1489 | static void | ||
1490 | mptscsih_send_raid_event(MPT_ADAPTER *ioc, | ||
1491 | EVENT_DATA_RAID *raid_event_data) | ||
1492 | { | ||
1493 | struct mptsas_hotplug_event *ev; | ||
1494 | RAID_VOL0_STATUS * volumeStatus; | ||
1495 | |||
1496 | if (ioc->bus_type != SAS) | ||
1497 | return; | ||
1498 | |||
1499 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
1500 | if (!ev) { | ||
1501 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | ||
1502 | return; | ||
1503 | } | ||
1504 | |||
1505 | memset(ev,0,sizeof(struct mptsas_hotplug_event)); | ||
1506 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); | ||
1507 | ev->ioc = ioc; | ||
1508 | ev->id = raid_event_data->VolumeID; | ||
1509 | |||
1510 | switch (raid_event_data->ReasonCode) { | ||
1511 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: | ||
1512 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
1513 | break; | ||
1514 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | ||
1515 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
1516 | break; | ||
1517 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | ||
1518 | ev->event_type = MPTSAS_DEL_RAID; | ||
1519 | break; | ||
1520 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: | ||
1521 | ev->event_type = MPTSAS_ADD_RAID; | ||
1522 | break; | ||
1523 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: | ||
1524 | volumeStatus = (RAID_VOL0_STATUS *) & | ||
1525 | raid_event_data->SettingsStatus; | ||
1526 | ev->event_type = (volumeStatus->State == | ||
1527 | MPI_RAIDVOL0_STATUS_STATE_FAILED) ? | ||
1528 | MPTSAS_DEL_RAID : MPTSAS_ADD_RAID; | ||
1529 | break; | ||
1530 | default: | ||
1531 | break; | ||
1532 | } | ||
1533 | schedule_work(&ev->work); | ||
1534 | } | ||
1535 | |||
1536 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
1537 | /* work queue thread to clear the persitency table */ | ||
1538 | static void | ||
1539 | mptscsih_sas_persist_clear_table(void * arg) | ||
1540 | { | ||
1541 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | ||
1542 | |||
1543 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
1544 | } | ||
1545 | |||
1375 | static int | 1546 | static int |
1376 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 1547 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
1377 | { | 1548 | { |
1549 | int rc=1; | ||
1378 | u8 event = le32_to_cpu(reply->Event) & 0xFF; | 1550 | u8 event = le32_to_cpu(reply->Event) & 0xFF; |
1379 | 1551 | ||
1380 | if (!ioc->sh) | 1552 | if (!ioc->sh) |
1381 | return 1; | 1553 | goto out; |
1382 | 1554 | ||
1383 | switch (event) { | 1555 | switch (event) { |
1384 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 1556 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
1385 | mptscsih_send_sas_event(ioc, | 1557 | mptscsih_send_sas_event(ioc, |
1386 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); | 1558 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); |
1387 | return 1; /* currently means nothing really */ | 1559 | break; |
1388 | 1560 | case MPI_EVENT_INTEGRATED_RAID: | |
1561 | mptscsih_send_raid_event(ioc, | ||
1562 | (EVENT_DATA_RAID *)reply->Data); | ||
1563 | break; | ||
1564 | case MPI_EVENT_PERSISTENT_TABLE_FULL: | ||
1565 | INIT_WORK(&ioc->mptscsih_persistTask, | ||
1566 | mptscsih_sas_persist_clear_table, | ||
1567 | (void *)ioc); | ||
1568 | schedule_work(&ioc->mptscsih_persistTask); | ||
1569 | break; | ||
1389 | default: | 1570 | default: |
1390 | return mptscsih_event_process(ioc, reply); | 1571 | rc = mptscsih_event_process(ioc, reply); |
1572 | break; | ||
1391 | } | 1573 | } |
1574 | out: | ||
1575 | |||
1576 | return rc; | ||
1392 | } | 1577 | } |
1393 | 1578 | ||
1394 | static int | 1579 | static int |