diff options
| -rw-r--r-- | drivers/message/fusion/mptbase.h | 4 | ||||
| -rw-r--r-- | drivers/message/fusion/mptsas.c | 354 |
2 files changed, 289 insertions, 69 deletions
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 9b58234add36..892af47cb91c 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
| @@ -619,6 +619,10 @@ typedef struct _MPT_ADAPTER | |||
| 619 | struct net_device *netdev; | 619 | struct net_device *netdev; |
| 620 | struct list_head sas_topology; | 620 | struct list_head sas_topology; |
| 621 | struct mutex sas_topology_mutex; | 621 | struct mutex sas_topology_mutex; |
| 622 | struct mutex sas_discovery_mutex; | ||
| 623 | u8 sas_discovery_runtime; | ||
| 624 | u8 sas_discovery_ignore_events; | ||
| 625 | int sas_index; /* index refrencing */ | ||
| 622 | MPT_SAS_MGMT sas_mgmt; | 626 | MPT_SAS_MGMT sas_mgmt; |
| 623 | int num_ports; | 627 | int num_ports; |
| 624 | struct work_struct mptscsih_persistTask; | 628 | struct work_struct mptscsih_persistTask; |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 289fcdbe89ba..be4eb8a308b7 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
| @@ -108,6 +108,11 @@ struct mptsas_hotplug_event { | |||
| 108 | u8 phys_disk_num_valid; | 108 | u8 phys_disk_num_valid; |
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | struct mptsas_discovery_event { | ||
| 112 | struct work_struct work; | ||
| 113 | MPT_ADAPTER *ioc; | ||
| 114 | }; | ||
| 115 | |||
| 111 | /* | 116 | /* |
| 112 | * SAS topology structures | 117 | * SAS topology structures |
| 113 | * | 118 | * |
| @@ -163,7 +168,6 @@ struct mptsas_enclosure { | |||
| 163 | u8 sep_channel; /* SEP channel logical channel id */ | 168 | u8 sep_channel; /* SEP channel logical channel id */ |
| 164 | }; | 169 | }; |
| 165 | 170 | ||
| 166 | |||
| 167 | #ifdef SASDEBUG | 171 | #ifdef SASDEBUG |
| 168 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 172 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
| 169 | { | 173 | { |
| @@ -273,6 +277,27 @@ static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | |||
| 273 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | 277 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; |
| 274 | } | 278 | } |
| 275 | 279 | ||
| 280 | /* | ||
| 281 | * mptsas_find_portinfo_by_handle | ||
| 282 | * | ||
| 283 | * This function should be called with the sas_topology_mutex already held | ||
| 284 | */ | ||
| 285 | static struct mptsas_portinfo * | ||
| 286 | mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | ||
| 287 | { | ||
| 288 | struct mptsas_portinfo *port_info, *rc=NULL; | ||
| 289 | int i; | ||
| 290 | |||
| 291 | list_for_each_entry(port_info, &ioc->sas_topology, list) | ||
| 292 | for (i = 0; i < port_info->num_phys; i++) | ||
| 293 | if (port_info->phy_info[i].identify.handle == handle) { | ||
| 294 | rc = port_info; | ||
| 295 | goto out; | ||
| 296 | } | ||
| 297 | out: | ||
| 298 | return rc; | ||
| 299 | } | ||
| 300 | |||
| 276 | static int | 301 | static int |
| 277 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | 302 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, |
| 278 | u32 form, u32 form_specific) | 303 | u32 form, u32 form_specific) |
| @@ -423,33 +448,9 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
| 423 | { | 448 | { |
| 424 | struct Scsi_Host *host = sdev->host; | 449 | struct Scsi_Host *host = sdev->host; |
| 425 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; | 450 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; |
| 426 | struct sas_rphy *rphy; | ||
| 427 | struct mptsas_portinfo *p; | ||
| 428 | int i; | ||
| 429 | VirtDevice *vdev; | 451 | VirtDevice *vdev; |
| 430 | 452 | ||
| 431 | /* | 453 | /* |
| 432 | * Handle hotplug removal case. | ||
| 433 | * We need to clear out attached data structure. | ||
| 434 | */ | ||
| 435 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); | ||
| 436 | |||
| 437 | mutex_lock(&hd->ioc->sas_topology_mutex); | ||
| 438 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { | ||
| 439 | for (i = 0; i < p->num_phys; i++) { | ||
| 440 | if (p->phy_info[i].attached.sas_address == | ||
| 441 | rphy->identify.sas_address) { | ||
| 442 | memset(&p->phy_info[i].attached, 0, | ||
| 443 | sizeof(struct mptsas_devinfo)); | ||
| 444 | p->phy_info[i].rphy = NULL; | ||
| 445 | goto out; | ||
| 446 | } | ||
| 447 | } | ||
| 448 | } | ||
| 449 | |||
| 450 | out: | ||
| 451 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 452 | /* | ||
| 453 | * Issue target reset to flush firmware outstanding commands. | 454 | * Issue target reset to flush firmware outstanding commands. |
| 454 | */ | 455 | */ |
| 455 | vdev = sdev->hostdata; | 456 | vdev = sdev->hostdata; |
| @@ -1044,7 +1045,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
| 1044 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); | 1045 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); |
| 1045 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); | 1046 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); |
| 1046 | 1047 | ||
| 1047 | |||
| 1048 | out_free_consistent: | 1048 | out_free_consistent: |
| 1049 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | 1049 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, |
| 1050 | buffer, dma_handle); | 1050 | buffer, dma_handle); |
| @@ -1134,12 +1134,19 @@ mptsas_parse_device_info(struct sas_identify *identify, | |||
| 1134 | static int mptsas_probe_one_phy(struct device *dev, | 1134 | static int mptsas_probe_one_phy(struct device *dev, |
| 1135 | struct mptsas_phyinfo *phy_info, int index, int local) | 1135 | struct mptsas_phyinfo *phy_info, int index, int local) |
| 1136 | { | 1136 | { |
| 1137 | MPT_ADAPTER *ioc; | ||
| 1137 | struct sas_phy *phy; | 1138 | struct sas_phy *phy; |
| 1138 | int error; | 1139 | int error; |
| 1139 | 1140 | ||
| 1140 | phy = sas_phy_alloc(dev, index); | 1141 | if (!dev) |
| 1141 | if (!phy) | 1142 | return -ENODEV; |
| 1142 | return -ENOMEM; | 1143 | |
| 1144 | if (!phy_info->phy) { | ||
| 1145 | phy = sas_phy_alloc(dev, index); | ||
| 1146 | if (!phy) | ||
| 1147 | return -ENOMEM; | ||
| 1148 | } else | ||
| 1149 | phy = phy_info->phy; | ||
| 1143 | 1150 | ||
| 1144 | phy->port_identifier = phy_info->port_id; | 1151 | phy->port_identifier = phy_info->port_id; |
| 1145 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); | 1152 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); |
| @@ -1225,19 +1232,35 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 1225 | break; | 1232 | break; |
| 1226 | } | 1233 | } |
| 1227 | 1234 | ||
| 1228 | if (local) | 1235 | if (!phy_info->phy) { |
| 1229 | phy->local_attached = 1; | ||
| 1230 | 1236 | ||
| 1231 | error = sas_phy_add(phy); | 1237 | if (local) |
| 1232 | if (error) { | 1238 | phy->local_attached = 1; |
| 1233 | sas_phy_free(phy); | 1239 | |
| 1234 | return error; | 1240 | error = sas_phy_add(phy); |
| 1241 | if (error) { | ||
| 1242 | sas_phy_free(phy); | ||
| 1243 | return error; | ||
| 1244 | } | ||
| 1245 | phy_info->phy = phy; | ||
| 1235 | } | 1246 | } |
| 1236 | phy_info->phy = phy; | ||
| 1237 | 1247 | ||
| 1238 | if (phy_info->attached.handle) { | 1248 | if ((phy_info->attached.handle) && |
| 1249 | (!phy_info->rphy)) { | ||
| 1250 | |||
| 1239 | struct sas_rphy *rphy; | 1251 | struct sas_rphy *rphy; |
| 1240 | 1252 | ||
| 1253 | ioc = phy_to_ioc(phy_info->phy); | ||
| 1254 | |||
| 1255 | /* | ||
| 1256 | * Let the hotplug_work thread handle processing | ||
| 1257 | * the adding/removing of devices that occur | ||
| 1258 | * after start of day. | ||
| 1259 | */ | ||
| 1260 | if (ioc->sas_discovery_runtime && | ||
| 1261 | mptsas_is_end_device(&phy_info->attached)) | ||
| 1262 | return 0; | ||
| 1263 | |||
| 1241 | rphy = sas_rphy_alloc(phy); | 1264 | rphy = sas_rphy_alloc(phy); |
| 1242 | if (!rphy) | 1265 | if (!rphy) |
| 1243 | return 0; /* non-fatal: an rphy can be added later */ | 1266 | return 0; /* non-fatal: an rphy can be added later */ |
| @@ -1256,24 +1279,37 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 1256 | } | 1279 | } |
| 1257 | 1280 | ||
| 1258 | static int | 1281 | static int |
| 1259 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | 1282 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc) |
| 1260 | { | 1283 | { |
| 1261 | struct mptsas_portinfo *port_info; | 1284 | struct mptsas_portinfo *port_info, *hba; |
| 1262 | u32 handle = 0xFFFF; | 1285 | u32 handle = 0xFFFF; |
| 1263 | int error = -ENOMEM, i; | 1286 | int error = -ENOMEM, i; |
| 1264 | 1287 | ||
| 1265 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1288 | hba = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 1266 | if (!port_info) | 1289 | if (! hba) |
| 1267 | goto out; | 1290 | goto out; |
| 1268 | 1291 | ||
| 1269 | error = mptsas_sas_io_unit_pg0(ioc, port_info); | 1292 | error = mptsas_sas_io_unit_pg0(ioc, hba); |
| 1270 | if (error) | 1293 | if (error) |
| 1271 | goto out_free_port_info; | 1294 | goto out_free_port_info; |
| 1272 | 1295 | ||
| 1273 | ioc->num_ports = port_info->num_phys; | ||
| 1274 | mutex_lock(&ioc->sas_topology_mutex); | 1296 | mutex_lock(&ioc->sas_topology_mutex); |
| 1275 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1297 | port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); |
| 1298 | if (!port_info) { | ||
| 1299 | port_info = hba; | ||
| 1300 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
| 1301 | } else { | ||
| 1302 | port_info->handle = hba->handle; | ||
| 1303 | for (i = 0; i < hba->num_phys; i++) | ||
| 1304 | port_info->phy_info[i].negotiated_link_rate = | ||
| 1305 | hba->phy_info[i].negotiated_link_rate; | ||
| 1306 | if (hba->phy_info) | ||
| 1307 | kfree(hba->phy_info); | ||
| 1308 | kfree(hba); | ||
| 1309 | hba = NULL; | ||
| 1310 | } | ||
| 1276 | mutex_unlock(&ioc->sas_topology_mutex); | 1311 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1312 | ioc->num_ports = port_info->num_phys; | ||
| 1277 | 1313 | ||
| 1278 | for (i = 0; i < port_info->num_phys; i++) { | 1314 | for (i = 0; i < port_info->num_phys; i++) { |
| 1279 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 1315 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
| @@ -1296,38 +1332,49 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | |||
| 1296 | } | 1332 | } |
| 1297 | 1333 | ||
| 1298 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, | 1334 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, |
| 1299 | &port_info->phy_info[i], *index, 1); | 1335 | &port_info->phy_info[i], ioc->sas_index, 1); |
| 1300 | (*index)++; | 1336 | ioc->sas_index++; |
| 1301 | } | 1337 | } |
| 1302 | 1338 | ||
| 1303 | return 0; | 1339 | return 0; |
| 1304 | 1340 | ||
| 1305 | out_free_port_info: | 1341 | out_free_port_info: |
| 1306 | kfree(port_info); | 1342 | if (hba) |
| 1343 | kfree(hba); | ||
| 1307 | out: | 1344 | out: |
| 1308 | return error; | 1345 | return error; |
| 1309 | } | 1346 | } |
| 1310 | 1347 | ||
| 1311 | static int | 1348 | static int |
| 1312 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | 1349 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) |
| 1313 | { | 1350 | { |
| 1314 | struct mptsas_portinfo *port_info, *p; | 1351 | struct mptsas_portinfo *port_info, *p, *ex; |
| 1315 | int error = -ENOMEM, i, j; | 1352 | int error = -ENOMEM, i, j; |
| 1316 | 1353 | ||
| 1317 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1354 | ex = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 1318 | if (!port_info) | 1355 | if (!ex) |
| 1319 | goto out; | 1356 | goto out; |
| 1320 | 1357 | ||
| 1321 | error = mptsas_sas_expander_pg0(ioc, port_info, | 1358 | error = mptsas_sas_expander_pg0(ioc, ex, |
| 1322 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | 1359 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
| 1323 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); | 1360 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); |
| 1324 | if (error) | 1361 | if (error) |
| 1325 | goto out_free_port_info; | 1362 | goto out_free_port_info; |
| 1326 | 1363 | ||
| 1327 | *handle = port_info->handle; | 1364 | *handle = ex->handle; |
| 1328 | 1365 | ||
| 1329 | mutex_lock(&ioc->sas_topology_mutex); | 1366 | mutex_lock(&ioc->sas_topology_mutex); |
| 1330 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1367 | port_info = mptsas_find_portinfo_by_handle(ioc, *handle); |
| 1368 | if (!port_info) { | ||
| 1369 | port_info = ex; | ||
| 1370 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
| 1371 | } else { | ||
| 1372 | port_info->handle = ex->handle; | ||
| 1373 | if (ex->phy_info) | ||
| 1374 | kfree(ex->phy_info); | ||
| 1375 | kfree(ex); | ||
| 1376 | ex = NULL; | ||
| 1377 | } | ||
| 1331 | mutex_unlock(&ioc->sas_topology_mutex); | 1378 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1332 | 1379 | ||
| 1333 | for (i = 0; i < port_info->num_phys; i++) { | 1380 | for (i = 0; i < port_info->num_phys; i++) { |
| @@ -1374,28 +1421,101 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1374 | mutex_unlock(&ioc->sas_topology_mutex); | 1421 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1375 | 1422 | ||
| 1376 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 1423 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], |
| 1377 | *index, 0); | 1424 | ioc->sas_index, 0); |
| 1378 | (*index)++; | 1425 | ioc->sas_index++; |
| 1379 | } | 1426 | } |
| 1380 | 1427 | ||
| 1381 | return 0; | 1428 | return 0; |
| 1382 | 1429 | ||
| 1383 | out_free_port_info: | 1430 | out_free_port_info: |
| 1384 | kfree(port_info->phy_info); | 1431 | if (ex) { |
| 1385 | kfree(port_info); | 1432 | if (ex->phy_info) |
| 1433 | kfree(ex->phy_info); | ||
| 1434 | kfree(ex); | ||
| 1435 | } | ||
| 1386 | out: | 1436 | out: |
| 1387 | return error; | 1437 | return error; |
| 1388 | } | 1438 | } |
| 1389 | 1439 | ||
| 1440 | /* | ||
| 1441 | * mptsas_delete_expander_phys | ||
| 1442 | * | ||
| 1443 | * | ||
| 1444 | * This will traverse topology, and remove expanders | ||
| 1445 | * that are no longer present | ||
| 1446 | */ | ||
| 1447 | static void | ||
| 1448 | mptsas_delete_expander_phys(MPT_ADAPTER *ioc) | ||
| 1449 | { | ||
| 1450 | struct mptsas_portinfo buffer; | ||
| 1451 | struct mptsas_portinfo *port_info, *n, *parent; | ||
| 1452 | int i; | ||
| 1453 | |||
| 1454 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1455 | list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { | ||
| 1456 | |||
| 1457 | if (port_info->phy_info && | ||
| 1458 | (!(port_info->phy_info[0].identify.device_info & | ||
| 1459 | MPI_SAS_DEVICE_INFO_SMP_TARGET))) | ||
| 1460 | continue; | ||
| 1461 | |||
| 1462 | if (mptsas_sas_expander_pg0(ioc, &buffer, | ||
| 1463 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
| 1464 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { | ||
| 1465 | |||
| 1466 | /* | ||
| 1467 | * Obtain the port_info instance to the parent port | ||
| 1468 | */ | ||
| 1469 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
| 1470 | port_info->phy_info[0].identify.handle_parent); | ||
| 1471 | |||
| 1472 | if (!parent) | ||
| 1473 | goto next_port; | ||
| 1474 | |||
| 1475 | /* | ||
| 1476 | * Delete rphys in the parent that point | ||
| 1477 | * to this expander. The transport layer will | ||
| 1478 | * cleanup all the children. | ||
| 1479 | */ | ||
| 1480 | for (i = 0; i < parent->num_phys; i++) { | ||
| 1481 | if ((!parent->phy_info[i].rphy) || | ||
| 1482 | (parent->phy_info[i].attached.sas_address != | ||
| 1483 | port_info->phy_info[i].identify.sas_address)) | ||
| 1484 | continue; | ||
| 1485 | sas_rphy_delete(parent->phy_info[i].rphy); | ||
| 1486 | memset(&parent->phy_info[i].attached, 0, | ||
| 1487 | sizeof(struct mptsas_devinfo)); | ||
| 1488 | parent->phy_info[i].rphy = NULL; | ||
| 1489 | parent->phy_info[i].starget = NULL; | ||
| 1490 | } | ||
| 1491 | next_port: | ||
| 1492 | list_del(&port_info->list); | ||
| 1493 | if (port_info->phy_info) | ||
| 1494 | kfree(port_info->phy_info); | ||
| 1495 | kfree(port_info); | ||
| 1496 | } | ||
| 1497 | /* | ||
| 1498 | * Free this memory allocated from inside | ||
| 1499 | * mptsas_sas_expander_pg0 | ||
| 1500 | */ | ||
| 1501 | if (buffer.phy_info) | ||
| 1502 | kfree(buffer.phy_info); | ||
| 1503 | } | ||
| 1504 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | /* | ||
| 1508 | * Start of day discovery | ||
| 1509 | */ | ||
| 1390 | static void | 1510 | static void |
| 1391 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | 1511 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
| 1392 | { | 1512 | { |
| 1393 | u32 handle = 0xFFFF; | 1513 | u32 handle = 0xFFFF; |
| 1394 | int index = 0; | ||
| 1395 | int i; | 1514 | int i; |
| 1396 | 1515 | ||
| 1397 | mptsas_probe_hba_phys(ioc, &index); | 1516 | mutex_lock(&ioc->sas_discovery_mutex); |
| 1398 | while (!mptsas_probe_expander_phys(ioc, &handle, &index)) | 1517 | mptsas_probe_hba_phys(ioc); |
| 1518 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1399 | ; | 1519 | ; |
| 1400 | /* | 1520 | /* |
| 1401 | Reporting RAID volumes. | 1521 | Reporting RAID volumes. |
| @@ -1409,7 +1529,29 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | |||
| 1409 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | 1529 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); |
| 1410 | } | 1530 | } |
| 1411 | out: | 1531 | out: |
| 1412 | return; | 1532 | mutex_unlock(&ioc->sas_discovery_mutex); |
| 1533 | } | ||
| 1534 | |||
| 1535 | /* | ||
| 1536 | * Work queue thread to handle Runtime discovery | ||
| 1537 | * Mere purpose is the hot add/delete of expanders | ||
| 1538 | */ | ||
| 1539 | static void | ||
| 1540 | mptscsih_discovery_work(void * arg) | ||
| 1541 | { | ||
| 1542 | struct mptsas_discovery_event *ev = arg; | ||
| 1543 | MPT_ADAPTER *ioc = ev->ioc; | ||
| 1544 | u32 handle = 0xFFFF; | ||
| 1545 | |||
| 1546 | mutex_lock(&ioc->sas_discovery_mutex); | ||
| 1547 | ioc->sas_discovery_runtime=1; | ||
| 1548 | mptsas_delete_expander_phys(ioc); | ||
| 1549 | mptsas_probe_hba_phys(ioc); | ||
| 1550 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1551 | ; | ||
| 1552 | kfree(ev); | ||
| 1553 | ioc->sas_discovery_runtime=0; | ||
| 1554 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
| 1413 | } | 1555 | } |
| 1414 | 1556 | ||
| 1415 | static struct mptsas_phyinfo * | 1557 | static struct mptsas_phyinfo * |
| @@ -1427,10 +1569,8 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | |||
| 1427 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 1569 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
| 1428 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 1570 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
| 1429 | parent_handle); | 1571 | parent_handle); |
| 1430 | if (error) { | 1572 | if (error) |
| 1431 | printk("mptsas: failed to retrieve device page\n"); | ||
| 1432 | return NULL; | 1573 | return NULL; |
| 1433 | } | ||
| 1434 | 1574 | ||
| 1435 | /* | 1575 | /* |
| 1436 | * The phy_info structures are never deallocated during lifetime of | 1576 | * The phy_info structures are never deallocated during lifetime of |
| @@ -1502,6 +1642,10 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) | |||
| 1502 | mptsas_reprobe_lun); | 1642 | mptsas_reprobe_lun); |
| 1503 | } | 1643 | } |
| 1504 | 1644 | ||
| 1645 | |||
| 1646 | /* | ||
| 1647 | * Work queue thread to handle SAS hotplug events | ||
| 1648 | */ | ||
| 1505 | static void | 1649 | static void |
| 1506 | mptsas_hotplug_work(void *arg) | 1650 | mptsas_hotplug_work(void *arg) |
| 1507 | { | 1651 | { |
| @@ -1514,10 +1658,13 @@ mptsas_hotplug_work(void *arg) | |||
| 1514 | struct mptsas_devinfo sas_device; | 1658 | struct mptsas_devinfo sas_device; |
| 1515 | VirtTarget *vtarget; | 1659 | VirtTarget *vtarget; |
| 1516 | 1660 | ||
| 1661 | mutex_lock(&ioc->sas_discovery_mutex); | ||
| 1662 | |||
| 1517 | switch (ev->event_type) { | 1663 | switch (ev->event_type) { |
| 1518 | case MPTSAS_DEL_DEVICE: | 1664 | case MPTSAS_DEL_DEVICE: |
| 1519 | 1665 | ||
| 1520 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); | 1666 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); |
| 1667 | |||
| 1521 | /* | 1668 | /* |
| 1522 | * Sanity checks, for non-existing phys and remote rphys. | 1669 | * Sanity checks, for non-existing phys and remote rphys. |
| 1523 | */ | 1670 | */ |
| @@ -1569,8 +1716,36 @@ mptsas_hotplug_work(void *arg) | |||
| 1569 | 1716 | ||
| 1570 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1717 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
| 1571 | sas_device.handle_parent, sas_device.phy_id); | 1718 | sas_device.handle_parent, sas_device.phy_id); |
| 1572 | if (!phy_info) | 1719 | |
| 1573 | break; | 1720 | if (!phy_info) { |
| 1721 | u32 handle = 0xFFFF; | ||
| 1722 | |||
| 1723 | /* | ||
| 1724 | * Its possible when an expander has been hot added | ||
| 1725 | * containing attached devices, the sas firmware | ||
| 1726 | * may send a RC_ADDED event prior to the | ||
| 1727 | * DISCOVERY STOP event. If that occurs, our | ||
| 1728 | * view of the topology in the driver in respect to this | ||
| 1729 | * expander might of not been setup, and we hit this | ||
| 1730 | * condition. | ||
| 1731 | * Therefore, this code kicks off discovery to | ||
| 1732 | * refresh the data. | ||
| 1733 | * Then again, we check whether the parent phy has | ||
| 1734 | * been created. | ||
| 1735 | */ | ||
| 1736 | ioc->sas_discovery_runtime=1; | ||
| 1737 | mptsas_delete_expander_phys(ioc); | ||
| 1738 | mptsas_probe_hba_phys(ioc); | ||
| 1739 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1740 | ; | ||
| 1741 | ioc->sas_discovery_runtime=0; | ||
| 1742 | |||
| 1743 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | ||
| 1744 | sas_device.handle_parent, sas_device.phy_id); | ||
| 1745 | if (!phy_info) | ||
| 1746 | break; | ||
| 1747 | } | ||
| 1748 | |||
| 1574 | if (phy_info->starget) { | 1749 | if (phy_info->starget) { |
| 1575 | vtarget = phy_info->starget->hostdata; | 1750 | vtarget = phy_info->starget->hostdata; |
| 1576 | 1751 | ||
| @@ -1604,7 +1779,6 @@ mptsas_hotplug_work(void *arg) | |||
| 1604 | "attaching %s device, channel %d, id %d, phy %d\n", | 1779 | "attaching %s device, channel %d, id %d, phy %d\n", |
| 1605 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | 1780 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); |
| 1606 | 1781 | ||
| 1607 | |||
| 1608 | rphy = sas_rphy_alloc(phy_info->phy); | 1782 | rphy = sas_rphy_alloc(phy_info->phy); |
| 1609 | if (!rphy) | 1783 | if (!rphy) |
| 1610 | break; /* non-fatal: an rphy can be added later */ | 1784 | break; /* non-fatal: an rphy can be added later */ |
| @@ -1654,6 +1828,7 @@ mptsas_hotplug_work(void *arg) | |||
| 1654 | } | 1828 | } |
| 1655 | 1829 | ||
| 1656 | kfree(ev); | 1830 | kfree(ev); |
| 1831 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
| 1657 | } | 1832 | } |
| 1658 | 1833 | ||
| 1659 | static void | 1834 | static void |
| @@ -1767,6 +1942,32 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, | |||
| 1767 | schedule_work(&ev->work); | 1942 | schedule_work(&ev->work); |
| 1768 | } | 1943 | } |
| 1769 | 1944 | ||
| 1945 | static void | ||
| 1946 | mptscsih_send_discovery(MPT_ADAPTER *ioc, | ||
| 1947 | EVENT_DATA_SAS_DISCOVERY *discovery_data) | ||
| 1948 | { | ||
| 1949 | struct mptsas_discovery_event *ev; | ||
| 1950 | |||
| 1951 | /* | ||
| 1952 | * DiscoveryStatus | ||
| 1953 | * | ||
| 1954 | * This flag will be non-zero when firmware | ||
| 1955 | * kicks off discovery, and return to zero | ||
| 1956 | * once its completed. | ||
| 1957 | */ | ||
| 1958 | if (discovery_data->DiscoveryStatus) | ||
| 1959 | return; | ||
| 1960 | |||
| 1961 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
| 1962 | if (!ev) | ||
| 1963 | return; | ||
| 1964 | memset(ev,0,sizeof(struct mptsas_discovery_event)); | ||
| 1965 | INIT_WORK(&ev->work, mptscsih_discovery_work, ev); | ||
| 1966 | ev->ioc = ioc; | ||
| 1967 | schedule_work(&ev->work); | ||
| 1968 | }; | ||
| 1969 | |||
| 1970 | |||
| 1770 | static int | 1971 | static int |
| 1771 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 1972 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
| 1772 | { | 1973 | { |
| @@ -1776,6 +1977,17 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
| 1776 | if (!ioc->sh) | 1977 | if (!ioc->sh) |
| 1777 | goto out; | 1978 | goto out; |
| 1778 | 1979 | ||
| 1980 | /* | ||
| 1981 | * sas_discovery_ignore_events | ||
| 1982 | * | ||
| 1983 | * This flag is to prevent anymore processing of | ||
| 1984 | * sas events once mptsas_remove function is called. | ||
| 1985 | */ | ||
| 1986 | if (ioc->sas_discovery_ignore_events) { | ||
| 1987 | rc = mptscsih_event_process(ioc, reply); | ||
| 1988 | goto out; | ||
| 1989 | } | ||
| 1990 | |||
| 1779 | switch (event) { | 1991 | switch (event) { |
| 1780 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 1992 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
| 1781 | mptscsih_send_sas_event(ioc, | 1993 | mptscsih_send_sas_event(ioc, |
| @@ -1792,6 +2004,9 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
| 1792 | schedule_work(&ioc->mptscsih_persistTask); | 2004 | schedule_work(&ioc->mptscsih_persistTask); |
| 1793 | break; | 2005 | break; |
| 1794 | case MPI_EVENT_SAS_DISCOVERY: | 2006 | case MPI_EVENT_SAS_DISCOVERY: |
| 2007 | mptscsih_send_discovery(ioc, | ||
| 2008 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | ||
| 2009 | break; | ||
| 1795 | default: | 2010 | default: |
| 1796 | rc = mptscsih_event_process(ioc, reply); | 2011 | rc = mptscsih_event_process(ioc, reply); |
| 1797 | break; | 2012 | break; |
| @@ -1893,7 +2108,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1893 | 2108 | ||
| 1894 | INIT_LIST_HEAD(&ioc->sas_topology); | 2109 | INIT_LIST_HEAD(&ioc->sas_topology); |
| 1895 | mutex_init(&ioc->sas_topology_mutex); | 2110 | mutex_init(&ioc->sas_topology_mutex); |
| 1896 | 2111 | mutex_init(&ioc->sas_discovery_mutex); | |
| 1897 | mutex_init(&ioc->sas_mgmt.mutex); | 2112 | mutex_init(&ioc->sas_mgmt.mutex); |
| 1898 | init_completion(&ioc->sas_mgmt.done); | 2113 | init_completion(&ioc->sas_mgmt.done); |
| 1899 | 2114 | ||
| @@ -2019,6 +2234,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
| 2019 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2234 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
| 2020 | struct mptsas_portinfo *p, *n; | 2235 | struct mptsas_portinfo *p, *n; |
| 2021 | 2236 | ||
| 2237 | ioc->sas_discovery_ignore_events=1; | ||
| 2022 | sas_remove_host(ioc->sh); | 2238 | sas_remove_host(ioc->sh); |
| 2023 | 2239 | ||
| 2024 | mutex_lock(&ioc->sas_topology_mutex); | 2240 | mutex_lock(&ioc->sas_topology_mutex); |
