diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
-rw-r--r-- | drivers/message/fusion/mptsas.c | 198 |
1 files changed, 173 insertions, 25 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 5a06d8d8694e..8e77837c07ec 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 */ |
@@ -714,6 +717,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
714 | mptsas_print_device_pg0(buffer); | 717 | mptsas_print_device_pg0(buffer); |
715 | 718 | ||
716 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 719 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
720 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | ||
717 | device_info->phy_id = buffer->PhyNum; | 721 | device_info->phy_id = buffer->PhyNum; |
718 | device_info->port_id = buffer->PhysicalPort; | 722 | device_info->port_id = buffer->PhysicalPort; |
719 | device_info->id = buffer->TargetID; | 723 | device_info->id = buffer->TargetID; |
@@ -863,6 +867,26 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
863 | return error; | 867 | return error; |
864 | } | 868 | } |
865 | 869 | ||
870 | /* | ||
871 | * Returns true if there is a scsi end device | ||
872 | */ | ||
873 | static inline int | ||
874 | mptsas_is_end_device(struct mptsas_devinfo * attached) | ||
875 | { | ||
876 | if ((attached->handle) && | ||
877 | (attached->device_info & | ||
878 | MPI_SAS_DEVICE_INFO_END_DEVICE) && | ||
879 | ((attached->device_info & | ||
880 | MPI_SAS_DEVICE_INFO_SSP_TARGET) | | ||
881 | (attached->device_info & | ||
882 | MPI_SAS_DEVICE_INFO_STP_TARGET) | | ||
883 | (attached->device_info & | ||
884 | MPI_SAS_DEVICE_INFO_SATA_DEVICE))) | ||
885 | return 1; | ||
886 | else | ||
887 | return 0; | ||
888 | } | ||
889 | |||
866 | static void | 890 | static void |
867 | mptsas_parse_device_info(struct sas_identify *identify, | 891 | mptsas_parse_device_info(struct sas_identify *identify, |
868 | struct mptsas_devinfo *device_info) | 892 | struct mptsas_devinfo *device_info) |
@@ -1227,7 +1251,7 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | |||
1227 | } | 1251 | } |
1228 | 1252 | ||
1229 | static struct mptsas_phyinfo * | 1253 | static struct mptsas_phyinfo * |
1230 | mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | 1254 | mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) |
1231 | { | 1255 | { |
1232 | struct mptsas_portinfo *port_info; | 1256 | struct mptsas_portinfo *port_info; |
1233 | struct mptsas_phyinfo *phy_info = NULL; | 1257 | struct mptsas_phyinfo *phy_info = NULL; |
@@ -1239,12 +1263,12 @@ mptsas_find_phyinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | |||
1239 | */ | 1263 | */ |
1240 | mutex_lock(&ioc->sas_topology_mutex); | 1264 | mutex_lock(&ioc->sas_topology_mutex); |
1241 | list_for_each_entry(port_info, &ioc->sas_topology, list) { | 1265 | list_for_each_entry(port_info, &ioc->sas_topology, list) { |
1242 | for (i = 0; i < port_info->num_phys; i++) { | 1266 | for (i = 0; i < port_info->num_phys; i++) |
1243 | if (port_info->phy_info[i].attached.handle == handle) { | 1267 | if (mptsas_is_end_device(&port_info->phy_info[i].attached)) |
1244 | phy_info = &port_info->phy_info[i]; | 1268 | if (port_info->phy_info[i].attached.id == id) { |
1245 | break; | 1269 | phy_info = &port_info->phy_info[i]; |
1246 | } | 1270 | break; |
1247 | } | 1271 | } |
1248 | } | 1272 | } |
1249 | mutex_unlock(&ioc->sas_topology_mutex); | 1273 | mutex_unlock(&ioc->sas_topology_mutex); |
1250 | 1274 | ||
@@ -1258,36 +1282,58 @@ mptsas_hotplug_work(void *arg) | |||
1258 | MPT_ADAPTER *ioc = ev->ioc; | 1282 | MPT_ADAPTER *ioc = ev->ioc; |
1259 | struct mptsas_phyinfo *phy_info; | 1283 | struct mptsas_phyinfo *phy_info; |
1260 | struct sas_rphy *rphy; | 1284 | struct sas_rphy *rphy; |
1285 | struct scsi_device *sdev; | ||
1261 | char *ds = NULL; | 1286 | char *ds = NULL; |
1262 | 1287 | 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 | 1288 | ||
1270 | switch (ev->event_type) { | 1289 | switch (ev->event_type) { |
1271 | case MPTSAS_DEL_DEVICE: | 1290 | 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 | 1291 | ||
1276 | phy_info = mptsas_find_phyinfo_by_handle(ioc, ev->handle); | 1292 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); |
1277 | if (!phy_info) { | 1293 | if (!phy_info) { |
1278 | printk("mptsas: remove event for non-existant PHY.\n"); | 1294 | printk("mptsas: remove event for non-existant PHY.\n"); |
1279 | break; | 1295 | break; |
1280 | } | 1296 | } |
1281 | 1297 | ||
1298 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1299 | ds = "ssp"; | ||
1300 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1301 | ds = "stp"; | ||
1302 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1303 | ds = "sata"; | ||
1304 | |||
1305 | printk(MYIOC_s_INFO_FMT | ||
1306 | "removing %s device, channel %d, id %d, phy %d\n", | ||
1307 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | ||
1308 | |||
1282 | if (phy_info->rphy) { | 1309 | if (phy_info->rphy) { |
1283 | sas_rphy_delete(phy_info->rphy); | 1310 | sas_rphy_delete(phy_info->rphy); |
1284 | phy_info->rphy = NULL; | 1311 | phy_info->rphy = NULL; |
1285 | } | 1312 | } |
1286 | break; | 1313 | break; |
1287 | case MPTSAS_ADD_DEVICE: | 1314 | case MPTSAS_ADD_DEVICE: |
1288 | printk(MYIOC_s_INFO_FMT | 1315 | |
1289 | "attaching %s device, channel %d, id %d, phy %d\n", | 1316 | /* |
1290 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | 1317 | * When there is no sas address, |
1318 | * RAID volumes are being deleted, | ||
1319 | * and hidden phy disk are being added. | ||
1320 | * We don't know the SAS data yet, | ||
1321 | * so lookup sas device page to get | ||
1322 | * pertaining info | ||
1323 | */ | ||
1324 | if (!ev->sas_address) { | ||
1325 | if (mptsas_sas_device_pg0(ioc, | ||
1326 | &sas_device, ev->id, | ||
1327 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | ||
1328 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT))) | ||
1329 | break; | ||
1330 | ev->handle = sas_device.handle; | ||
1331 | ev->parent_handle = sas_device.handle_parent; | ||
1332 | ev->channel = sas_device.channel; | ||
1333 | ev->phy_id = sas_device.phy_id; | ||
1334 | ev->sas_address = sas_device.sas_address; | ||
1335 | ev->device_info = sas_device.device_info; | ||
1336 | } | ||
1291 | 1337 | ||
1292 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1338 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
1293 | ev->parent_handle, ev->phy_id); | 1339 | ev->parent_handle, ev->phy_id); |
@@ -1310,10 +1356,23 @@ mptsas_hotplug_work(void *arg) | |||
1310 | phy_info->attached.sas_address = ev->sas_address; | 1356 | phy_info->attached.sas_address = ev->sas_address; |
1311 | phy_info->attached.device_info = ev->device_info; | 1357 | phy_info->attached.device_info = ev->device_info; |
1312 | 1358 | ||
1359 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | ||
1360 | ds = "ssp"; | ||
1361 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_STP_TARGET) | ||
1362 | ds = "stp"; | ||
1363 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SATA_DEVICE) | ||
1364 | ds = "sata"; | ||
1365 | |||
1366 | printk(MYIOC_s_INFO_FMT | ||
1367 | "attaching %s device, channel %d, id %d, phy %d\n", | ||
1368 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | ||
1369 | |||
1370 | |||
1313 | rphy = sas_rphy_alloc(phy_info->phy); | 1371 | rphy = sas_rphy_alloc(phy_info->phy); |
1314 | if (!rphy) | 1372 | if (!rphy) |
1315 | break; /* non-fatal: an rphy can be added later */ | 1373 | break; /* non-fatal: an rphy can be added later */ |
1316 | 1374 | ||
1375 | rphy->scsi_target_id = phy_info->attached.id; | ||
1317 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | 1376 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); |
1318 | if (sas_rphy_add(rphy)) { | 1377 | if (sas_rphy_add(rphy)) { |
1319 | sas_rphy_free(rphy); | 1378 | sas_rphy_free(rphy); |
@@ -1322,6 +1381,40 @@ mptsas_hotplug_work(void *arg) | |||
1322 | 1381 | ||
1323 | phy_info->rphy = rphy; | 1382 | phy_info->rphy = rphy; |
1324 | break; | 1383 | break; |
1384 | case MPTSAS_ADD_RAID: | ||
1385 | sdev = scsi_device_lookup( | ||
1386 | ioc->sh, | ||
1387 | ioc->num_ports, | ||
1388 | ev->id, | ||
1389 | 0); | ||
1390 | if (sdev) { | ||
1391 | scsi_device_put(sdev); | ||
1392 | break; | ||
1393 | } | ||
1394 | printk(MYIOC_s_INFO_FMT | ||
1395 | "attaching device, channel %d, id %d\n", | ||
1396 | ioc->name, ioc->num_ports, ev->id); | ||
1397 | scsi_add_device(ioc->sh, | ||
1398 | ioc->num_ports, | ||
1399 | ev->id, | ||
1400 | 0); | ||
1401 | mpt_findImVolumes(ioc); | ||
1402 | break; | ||
1403 | case MPTSAS_DEL_RAID: | ||
1404 | sdev = scsi_device_lookup( | ||
1405 | ioc->sh, | ||
1406 | ioc->num_ports, | ||
1407 | ev->id, | ||
1408 | 0); | ||
1409 | if (!sdev) | ||
1410 | break; | ||
1411 | printk(MYIOC_s_INFO_FMT | ||
1412 | "removing device, channel %d, id %d\n", | ||
1413 | ioc->name, ioc->num_ports, ev->id); | ||
1414 | scsi_remove_device(sdev); | ||
1415 | scsi_device_put(sdev); | ||
1416 | mpt_findImVolumes(ioc); | ||
1417 | break; | ||
1325 | } | 1418 | } |
1326 | 1419 | ||
1327 | kfree(ev); | 1420 | kfree(ev); |
@@ -1372,23 +1465,78 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, | |||
1372 | schedule_work(&ev->work); | 1465 | schedule_work(&ev->work); |
1373 | } | 1466 | } |
1374 | 1467 | ||
1468 | static void | ||
1469 | mptscsih_send_raid_event(MPT_ADAPTER *ioc, | ||
1470 | EVENT_DATA_RAID *raid_event_data) | ||
1471 | { | ||
1472 | struct mptsas_hotplug_event *ev; | ||
1473 | RAID_VOL0_STATUS * volumeStatus; | ||
1474 | |||
1475 | if (ioc->bus_type != SAS) | ||
1476 | return; | ||
1477 | |||
1478 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
1479 | if (!ev) { | ||
1480 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | ||
1481 | return; | ||
1482 | } | ||
1483 | |||
1484 | memset(ev,0,sizeof(struct mptsas_hotplug_event)); | ||
1485 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); | ||
1486 | ev->ioc = ioc; | ||
1487 | ev->id = raid_event_data->VolumeID; | ||
1488 | |||
1489 | switch (raid_event_data->ReasonCode) { | ||
1490 | case MPI_EVENT_RAID_RC_PHYSDISK_DELETED: | ||
1491 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
1492 | break; | ||
1493 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | ||
1494 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
1495 | break; | ||
1496 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | ||
1497 | ev->event_type = MPTSAS_DEL_RAID; | ||
1498 | break; | ||
1499 | case MPI_EVENT_RAID_RC_VOLUME_CREATED: | ||
1500 | ev->event_type = MPTSAS_ADD_RAID; | ||
1501 | break; | ||
1502 | case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED: | ||
1503 | volumeStatus = (RAID_VOL0_STATUS *) & | ||
1504 | raid_event_data->SettingsStatus; | ||
1505 | ev->event_type = (volumeStatus->State == | ||
1506 | MPI_RAIDVOL0_STATUS_STATE_FAILED) ? | ||
1507 | MPTSAS_DEL_RAID : MPTSAS_ADD_RAID; | ||
1508 | break; | ||
1509 | default: | ||
1510 | break; | ||
1511 | } | ||
1512 | schedule_work(&ev->work); | ||
1513 | } | ||
1514 | |||
1375 | static int | 1515 | static int |
1376 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 1516 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
1377 | { | 1517 | { |
1518 | int rc=1; | ||
1378 | u8 event = le32_to_cpu(reply->Event) & 0xFF; | 1519 | u8 event = le32_to_cpu(reply->Event) & 0xFF; |
1379 | 1520 | ||
1380 | if (!ioc->sh) | 1521 | if (!ioc->sh) |
1381 | return 1; | 1522 | goto out; |
1382 | 1523 | ||
1383 | switch (event) { | 1524 | switch (event) { |
1384 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 1525 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
1385 | mptscsih_send_sas_event(ioc, | 1526 | mptscsih_send_sas_event(ioc, |
1386 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); | 1527 | (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); |
1387 | return 1; /* currently means nothing really */ | 1528 | break; |
1388 | 1529 | case MPI_EVENT_INTEGRATED_RAID: | |
1530 | mptscsih_send_raid_event(ioc, | ||
1531 | (EVENT_DATA_RAID *)reply->Data); | ||
1532 | break; | ||
1389 | default: | 1533 | default: |
1390 | return mptscsih_event_process(ioc, reply); | 1534 | rc = mptscsih_event_process(ioc, reply); |
1535 | break; | ||
1391 | } | 1536 | } |
1537 | out: | ||
1538 | |||
1539 | return rc; | ||
1392 | } | 1540 | } |
1393 | 1541 | ||
1394 | static int | 1542 | static int |