aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMoore, Eric <Eric.Moore@lsil.com>2006-03-14 11:14:24 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-03-14 15:35:17 -0500
commite6b2d76a49f0ee48527691867d8af2b8f9c10452 (patch)
tree8f35dda5dcf65ccc740761c96924111baf0a8644 /drivers
parentf44e5461d919a344d44f7ca4f06cf8d169da8454 (diff)
[SCSI] fusion - expander hotplug suport in mptsas module
This adds support for hot adding and removing expanders, and its associated attached devices. When there is a change in topology, the fusion firmware sends the MPI_EVENT_SAS_DISCOVERY event to the driver. The driver will read firmware config pages to determine what changes took place, and refresh drivers view of the world stored in ioc->sas_topology. Here is the details of the action the driver does: (1) Expander Added : The mptsas_discovery_work workqueue is called. Config pages read, and ioc->sas_topology is refreshed. The sas_phy_add() is called for each phy of the expander. The expanders attached devices are added via sas_rphy_add(). Added end devices are handled within the MPT_ADD_DEVICE logic in mptsas_hotplug_work workqueue. (2) Expander Delete : The sas_rphy_delete() will be called for the top most compenent of the parent that the expander is attached to. The sas_rphy_delete call will delete all the children phys, rphys, and end devices. This is handled from mptsas_discovery_work workqueue. Signed-off-by: Eric Moore <Eric.Moore@lsil.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptsas.c354
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
111struct 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
168static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) 172static 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 */
285static struct mptsas_portinfo *
286mptsas_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
276static int 301static int
277mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, 302mptsas_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,
1134static int mptsas_probe_one_phy(struct device *dev, 1134static 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
1258static int 1281static int
1259mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) 1282mptsas_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
1311static int 1348static int
1312mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) 1349mptsas_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 */
1447static void
1448mptsas_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 */
1390static void 1510static void
1391mptsas_scan_sas_topology(MPT_ADAPTER *ioc) 1511mptsas_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 */
1539static void
1540mptscsih_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
1415static struct mptsas_phyinfo * 1557static 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 */
1505static void 1649static void
1506mptsas_hotplug_work(void *arg) 1650mptsas_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
1659static void 1834static 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
1945static void
1946mptscsih_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
1770static int 1971static int
1771mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) 1972mptsas_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);