aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2006-04-10 10:14:05 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-13 14:25:16 -0400
commitaedf349773e5877d716a89368d512b9baa3e8c7b (patch)
treeacc08d181b97c434c70c7ad984e262813067ba89 /drivers/scsi
parentb0d2364887e94c880680f1e17943cd660bcf8979 (diff)
[SCSI] FC transport: fixes for workq deadlocks
As previously reported via Michael Reed, the FC transport took a hit in 2.6.15 (perhaps a little earlier) when we solved a recursion error. There are 2 deadlocks occurring: - With scan and the delete items sharing the same workq, flushing the workq for the delete code was getting it stalled behind a very long running scan code path. - There's a deadlock where scsi_remove_target() has to sit behind scsi_scan_target() due to contention over the scan_lock(). This patch resolves the 1st deadlock and significantly reduces the odds of the second. So far, we have only replicated the 2nd deadlock on a highly-parallel SMP system. More on the 2nd deadlock in a following email. This patch reworks the transport to: - Only use the scsi host workq for scanning - Use 2 other workq's internally. One for deletions, the other for scheduled deletions. Originally, we tried this with a single workq, but the occassional flushes of the scheduled queues was hitting the second deadlock with a slightly higher frequency. In the future, we'll look at the LLDD's and the transport to see if we can get rid of this extra overhead. - When moving to the other workq's we tightened up some object states and some lock handling. - Properly syncs adds/deletes - minor code cleanups - directly reference fc_host_attrs, rather than through attribute macros - flush the right workq on delayed work cancel failures. Large kudos to Michael Reed who has been working this issue for the last month. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/scsi_transport_fc.c466
1 files changed, 311 insertions, 155 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 8db656214b5c..95c5478dcdfd 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -34,6 +34,8 @@
34#include <scsi/scsi_cmnd.h> 34#include <scsi/scsi_cmnd.h>
35#include "scsi_priv.h" 35#include "scsi_priv.h"
36 36
37static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
38
37/* 39/*
38 * Redefine so that we can have same named attributes in the 40 * Redefine so that we can have same named attributes in the
39 * sdev/starget/host objects. 41 * sdev/starget/host objects.
@@ -213,10 +215,8 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
213#define FC_MGMTSRVR_PORTID 0x00000a 215#define FC_MGMTSRVR_PORTID 0x00000a
214 216
215 217
216static void fc_shost_remove_rports(void *data);
217static void fc_timeout_deleted_rport(void *data); 218static void fc_timeout_deleted_rport(void *data);
218static void fc_scsi_scan_rport(void *data); 219static void fc_scsi_scan_rport(void *data);
219static void fc_rport_terminate(struct fc_rport *rport);
220 220
221/* 221/*
222 * Attribute counts pre object type... 222 * Attribute counts pre object type...
@@ -288,42 +288,58 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
288 struct class_device *cdev) 288 struct class_device *cdev)
289{ 289{
290 struct Scsi_Host *shost = dev_to_shost(dev); 290 struct Scsi_Host *shost = dev_to_shost(dev);
291 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
291 292
292 /* 293 /*
293 * Set default values easily detected by the midlayer as 294 * Set default values easily detected by the midlayer as
294 * failure cases. The scsi lldd is responsible for initializing 295 * failure cases. The scsi lldd is responsible for initializing
295 * all transport attributes to valid values per host. 296 * all transport attributes to valid values per host.
296 */ 297 */
297 fc_host_node_name(shost) = -1; 298 fc_host->node_name = -1;
298 fc_host_port_name(shost) = -1; 299 fc_host->port_name = -1;
299 fc_host_permanent_port_name(shost) = -1; 300 fc_host->permanent_port_name = -1;
300 fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED; 301 fc_host->supported_classes = FC_COS_UNSPECIFIED;
301 memset(fc_host_supported_fc4s(shost), 0, 302 memset(fc_host->supported_fc4s, 0,
302 sizeof(fc_host_supported_fc4s(shost))); 303 sizeof(fc_host->supported_fc4s));
303 memset(fc_host_symbolic_name(shost), 0, 304 memset(fc_host->symbolic_name, 0,
304 sizeof(fc_host_symbolic_name(shost))); 305 sizeof(fc_host->symbolic_name));
305 fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN; 306 fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
306 fc_host_maxframe_size(shost) = -1; 307 fc_host->maxframe_size = -1;
307 memset(fc_host_serial_number(shost), 0, 308 memset(fc_host->serial_number, 0,
308 sizeof(fc_host_serial_number(shost))); 309 sizeof(fc_host->serial_number));
309 310
310 fc_host_port_id(shost) = -1; 311 fc_host->port_id = -1;
311 fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; 312 fc_host->port_type = FC_PORTTYPE_UNKNOWN;
312 fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; 313 fc_host->port_state = FC_PORTSTATE_UNKNOWN;
313 memset(fc_host_active_fc4s(shost), 0, 314 memset(fc_host->active_fc4s, 0,
314 sizeof(fc_host_active_fc4s(shost))); 315 sizeof(fc_host->active_fc4s));
315 fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; 316 fc_host->speed = FC_PORTSPEED_UNKNOWN;
316 fc_host_fabric_name(shost) = -1; 317 fc_host->fabric_name = -1;
317 318
318 fc_host_tgtid_bind_type(shost) = FC_TGTID_BIND_BY_WWPN; 319 fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN;
319 320
320 INIT_LIST_HEAD(&fc_host_rports(shost)); 321 INIT_LIST_HEAD(&fc_host->rports);
321 INIT_LIST_HEAD(&fc_host_rport_bindings(shost)); 322 INIT_LIST_HEAD(&fc_host->rport_bindings);
322 fc_host_next_rport_number(shost) = 0; 323 fc_host->next_rport_number = 0;
323 fc_host_next_target_id(shost) = 0; 324 fc_host->next_target_id = 0;
324 325
325 fc_host_flags(shost) = 0; 326 snprintf(fc_host->work_q_name, KOBJ_NAME_LEN, "fc_wq_%d",
326 INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); 327 shost->host_no);
328 fc_host->work_q = create_singlethread_workqueue(
329 fc_host->work_q_name);
330 if (!fc_host->work_q)
331 return -ENOMEM;
332
333 snprintf(fc_host->devloss_work_q_name, KOBJ_NAME_LEN, "fc_dl_%d",
334 shost->host_no);
335 fc_host->devloss_work_q = create_singlethread_workqueue(
336 fc_host->devloss_work_q_name);
337 if (!fc_host->devloss_work_q) {
338 destroy_workqueue(fc_host->work_q);
339 fc_host->work_q = NULL;
340 return -ENOMEM;
341 }
342
327 return 0; 343 return 0;
328} 344}
329 345
@@ -879,9 +895,9 @@ store_fc_private_host_tgtid_bind_type(struct class_device *cdev,
879 while (!list_empty(&fc_host_rport_bindings(shost))) { 895 while (!list_empty(&fc_host_rport_bindings(shost))) {
880 get_list_head_entry(rport, 896 get_list_head_entry(rport,
881 &fc_host_rport_bindings(shost), peers); 897 &fc_host_rport_bindings(shost), peers);
882 spin_unlock_irqrestore(shost->host_lock, flags); 898 list_del(&rport->peers);
883 fc_rport_terminate(rport); 899 rport->port_state = FC_PORTSTATE_DELETED;
884 spin_lock_irqsave(shost->host_lock, flags); 900 fc_queue_work(shost, &rport->rport_delete_work);
885 } 901 }
886 spin_unlock_irqrestore(shost->host_lock, flags); 902 spin_unlock_irqrestore(shost->host_lock, flags);
887 } 903 }
@@ -1262,6 +1278,90 @@ void fc_release_transport(struct scsi_transport_template *t)
1262} 1278}
1263EXPORT_SYMBOL(fc_release_transport); 1279EXPORT_SYMBOL(fc_release_transport);
1264 1280
1281/**
1282 * fc_queue_work - Queue work to the fc_host workqueue.
1283 * @shost: Pointer to Scsi_Host bound to fc_host.
1284 * @work: Work to queue for execution.
1285 *
1286 * Return value:
1287 * 0 on success / != 0 for error
1288 **/
1289static int
1290fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
1291{
1292 if (unlikely(!fc_host_work_q(shost))) {
1293 printk(KERN_ERR
1294 "ERROR: FC host '%s' attempted to queue work, "
1295 "when no workqueue created.\n", shost->hostt->name);
1296 dump_stack();
1297
1298 return -EINVAL;
1299 }
1300
1301 return queue_work(fc_host_work_q(shost), work);
1302}
1303
1304/**
1305 * fc_flush_work - Flush a fc_host's workqueue.
1306 * @shost: Pointer to Scsi_Host bound to fc_host.
1307 **/
1308static void
1309fc_flush_work(struct Scsi_Host *shost)
1310{
1311 if (!fc_host_work_q(shost)) {
1312 printk(KERN_ERR
1313 "ERROR: FC host '%s' attempted to flush work, "
1314 "when no workqueue created.\n", shost->hostt->name);
1315 dump_stack();
1316 return;
1317 }
1318
1319 flush_workqueue(fc_host_work_q(shost));
1320}
1321
1322/**
1323 * fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue.
1324 * @shost: Pointer to Scsi_Host bound to fc_host.
1325 * @work: Work to queue for execution.
1326 * @delay: jiffies to delay the work queuing
1327 *
1328 * Return value:
1329 * 0 on success / != 0 for error
1330 **/
1331static int
1332fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
1333 unsigned long delay)
1334{
1335 if (unlikely(!fc_host_devloss_work_q(shost))) {
1336 printk(KERN_ERR
1337 "ERROR: FC host '%s' attempted to queue work, "
1338 "when no workqueue created.\n", shost->hostt->name);
1339 dump_stack();
1340
1341 return -EINVAL;
1342 }
1343
1344 return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
1345}
1346
1347/**
1348 * fc_flush_devloss - Flush a fc_host's devloss workqueue.
1349 * @shost: Pointer to Scsi_Host bound to fc_host.
1350 **/
1351static void
1352fc_flush_devloss(struct Scsi_Host *shost)
1353{
1354 if (!fc_host_devloss_work_q(shost)) {
1355 printk(KERN_ERR
1356 "ERROR: FC host '%s' attempted to flush work, "
1357 "when no workqueue created.\n", shost->hostt->name);
1358 dump_stack();
1359 return;
1360 }
1361
1362 flush_workqueue(fc_host_devloss_work_q(shost));
1363}
1364
1265 1365
1266/** 1366/**
1267 * fc_remove_host - called to terminate any fc_transport-related elements 1367 * fc_remove_host - called to terminate any fc_transport-related elements
@@ -1283,36 +1383,103 @@ void
1283fc_remove_host(struct Scsi_Host *shost) 1383fc_remove_host(struct Scsi_Host *shost)
1284{ 1384{
1285 struct fc_rport *rport, *next_rport; 1385 struct fc_rport *rport, *next_rport;
1386 struct workqueue_struct *work_q;
1387 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1286 1388
1287 /* Remove any remote ports */ 1389 /* Remove any remote ports */
1288 list_for_each_entry_safe(rport, next_rport, 1390 list_for_each_entry_safe(rport, next_rport,
1289 &fc_host_rports(shost), peers) 1391 &fc_host->rports, peers) {
1290 fc_rport_terminate(rport); 1392 list_del(&rport->peers);
1393 rport->port_state = FC_PORTSTATE_DELETED;
1394 fc_queue_work(shost, &rport->rport_delete_work);
1395 }
1396
1291 list_for_each_entry_safe(rport, next_rport, 1397 list_for_each_entry_safe(rport, next_rport,
1292 &fc_host_rport_bindings(shost), peers) 1398 &fc_host->rport_bindings, peers) {
1293 fc_rport_terminate(rport); 1399 list_del(&rport->peers);
1400 rport->port_state = FC_PORTSTATE_DELETED;
1401 fc_queue_work(shost, &rport->rport_delete_work);
1402 }
1403
1404 /* flush all scan work items */
1405 scsi_flush_work(shost);
1406
1407 /* flush all stgt delete, and rport delete work items, then kill it */
1408 if (fc_host->work_q) {
1409 work_q = fc_host->work_q;
1410 fc_host->work_q = NULL;
1411 destroy_workqueue(work_q);
1412 }
1413
1414 /* flush all devloss work items, then kill it */
1415 if (fc_host->devloss_work_q) {
1416 work_q = fc_host->devloss_work_q;
1417 fc_host->devloss_work_q = NULL;
1418 destroy_workqueue(work_q);
1419 }
1294} 1420}
1295EXPORT_SYMBOL(fc_remove_host); 1421EXPORT_SYMBOL(fc_remove_host);
1296 1422
1297/* 1423
1298 * fc_rport_tgt_remove - Removes the scsi target on the remote port 1424/**
1299 * @rport: The remote port to be operated on 1425 * fc_starget_delete - called to delete the scsi decendents of an rport
1300 */ 1426 * (target and all sdevs)
1427 *
1428 * @data: remote port to be operated on.
1429 **/
1301static void 1430static void
1302fc_rport_tgt_remove(struct fc_rport *rport) 1431fc_starget_delete(void *data)
1303{ 1432{
1433 struct fc_rport *rport = (struct fc_rport *)data;
1304 struct Scsi_Host *shost = rport_to_shost(rport); 1434 struct Scsi_Host *shost = rport_to_shost(rport);
1435 unsigned long flags;
1305 1436
1306 scsi_target_unblock(&rport->dev); 1437 scsi_target_unblock(&rport->dev);
1307 1438
1308 /* Stop anything on the workq */ 1439 spin_lock_irqsave(shost->host_lock, flags);
1309 if (!cancel_delayed_work(&rport->dev_loss_work)) 1440 if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
1310 flush_scheduled_work(); 1441 spin_unlock_irqrestore(shost->host_lock, flags);
1311 scsi_flush_work(shost); 1442 if (!cancel_delayed_work(&rport->dev_loss_work))
1443 fc_flush_devloss(shost);
1444 spin_lock_irqsave(shost->host_lock, flags);
1445 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
1446 }
1447 spin_unlock_irqrestore(shost->host_lock, flags);
1312 1448
1313 scsi_remove_target(&rport->dev); 1449 scsi_remove_target(&rport->dev);
1314} 1450}
1315 1451
1452
1453/**
1454 * fc_rport_final_delete - finish rport termination and delete it.
1455 *
1456 * @data: remote port to be deleted.
1457 **/
1458static void
1459fc_rport_final_delete(void *data)
1460{
1461 struct fc_rport *rport = (struct fc_rport *)data;
1462 struct device *dev = &rport->dev;
1463 struct Scsi_Host *shost = rport_to_shost(rport);
1464
1465 /* Delete SCSI target and sdevs */
1466 if (rport->scsi_target_id != -1)
1467 fc_starget_delete(data);
1468
1469 /*
1470 * if a scan is pending, flush the SCSI Host work_q so that
1471 * that we can reclaim the rport scan work element.
1472 */
1473 if (rport->flags & FC_RPORT_SCAN_PENDING)
1474 scsi_flush_work(shost);
1475
1476 transport_remove_device(dev);
1477 device_del(dev);
1478 transport_destroy_device(dev);
1479 put_device(&shost->shost_gendev);
1480}
1481
1482
1316/** 1483/**
1317 * fc_rport_create - allocates and creates a remote FC port. 1484 * fc_rport_create - allocates and creates a remote FC port.
1318 * @shost: scsi host the remote port is connected to. 1485 * @shost: scsi host the remote port is connected to.
@@ -1330,8 +1497,7 @@ struct fc_rport *
1330fc_rport_create(struct Scsi_Host *shost, int channel, 1497fc_rport_create(struct Scsi_Host *shost, int channel,
1331 struct fc_rport_identifiers *ids) 1498 struct fc_rport_identifiers *ids)
1332{ 1499{
1333 struct fc_host_attrs *fc_host = 1500 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1334 (struct fc_host_attrs *)shost->shost_data;
1335 struct fc_internal *fci = to_fc_internal(shost->transportt); 1501 struct fc_internal *fci = to_fc_internal(shost->transportt);
1336 struct fc_rport *rport; 1502 struct fc_rport *rport;
1337 struct device *dev; 1503 struct device *dev;
@@ -1360,6 +1526,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
1360 1526
1361 INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); 1527 INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
1362 INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); 1528 INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
1529 INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
1530 INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
1363 1531
1364 spin_lock_irqsave(shost->host_lock, flags); 1532 spin_lock_irqsave(shost->host_lock, flags);
1365 1533
@@ -1368,7 +1536,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
1368 rport->scsi_target_id = fc_host->next_target_id++; 1536 rport->scsi_target_id = fc_host->next_target_id++;
1369 else 1537 else
1370 rport->scsi_target_id = -1; 1538 rport->scsi_target_id = -1;
1371 list_add_tail(&rport->peers, &fc_host_rports(shost)); 1539 list_add_tail(&rport->peers, &fc_host->rports);
1372 get_device(&shost->shost_gendev); 1540 get_device(&shost->shost_gendev);
1373 1541
1374 spin_unlock_irqrestore(shost->host_lock, flags); 1542 spin_unlock_irqrestore(shost->host_lock, flags);
@@ -1389,9 +1557,11 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
1389 transport_add_device(dev); 1557 transport_add_device(dev);
1390 transport_configure_device(dev); 1558 transport_configure_device(dev);
1391 1559
1392 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) 1560 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
1393 /* initiate a scan of the target */ 1561 /* initiate a scan of the target */
1562 rport->flags |= FC_RPORT_SCAN_PENDING;
1394 scsi_queue_work(shost, &rport->scan_work); 1563 scsi_queue_work(shost, &rport->scan_work);
1564 }
1395 1565
1396 return rport; 1566 return rport;
1397 1567
@@ -1451,10 +1621,14 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1451 struct fc_rport_identifiers *ids) 1621 struct fc_rport_identifiers *ids)
1452{ 1622{
1453 struct fc_internal *fci = to_fc_internal(shost->transportt); 1623 struct fc_internal *fci = to_fc_internal(shost->transportt);
1624 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1454 struct fc_rport *rport; 1625 struct fc_rport *rport;
1455 unsigned long flags; 1626 unsigned long flags;
1456 int match = 0; 1627 int match = 0;
1457 1628
1629 /* ensure any stgt delete functions are done */
1630 fc_flush_work(shost);
1631
1458 /* 1632 /*
1459 * Search the list of "active" rports, for an rport that has been 1633 * Search the list of "active" rports, for an rport that has been
1460 * deleted, but we've held off the real delete while the target 1634 * deleted, but we've held off the real delete while the target
@@ -1462,12 +1636,12 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1462 */ 1636 */
1463 spin_lock_irqsave(shost->host_lock, flags); 1637 spin_lock_irqsave(shost->host_lock, flags);
1464 1638
1465 list_for_each_entry(rport, &fc_host_rports(shost), peers) { 1639 list_for_each_entry(rport, &fc_host->rports, peers) {
1466 1640
1467 if ((rport->port_state == FC_PORTSTATE_BLOCKED) && 1641 if ((rport->port_state == FC_PORTSTATE_BLOCKED) &&
1468 (rport->channel == channel)) { 1642 (rport->channel == channel)) {
1469 1643
1470 switch (fc_host_tgtid_bind_type(shost)) { 1644 switch (fc_host->tgtid_bind_type) {
1471 case FC_TGTID_BIND_BY_WWPN: 1645 case FC_TGTID_BIND_BY_WWPN:
1472 case FC_TGTID_BIND_NONE: 1646 case FC_TGTID_BIND_NONE:
1473 if (rport->port_name == ids->port_name) 1647 if (rport->port_name == ids->port_name)
@@ -1521,27 +1695,34 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1521 * transaction. 1695 * transaction.
1522 */ 1696 */
1523 if (!cancel_delayed_work(work)) 1697 if (!cancel_delayed_work(work))
1524 flush_scheduled_work(); 1698 fc_flush_devloss(shost);
1699
1700 spin_lock_irqsave(shost->host_lock, flags);
1701
1702 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
1525 1703
1526 /* initiate a scan of the target */ 1704 /* initiate a scan of the target */
1705 rport->flags |= FC_RPORT_SCAN_PENDING;
1527 scsi_queue_work(shost, &rport->scan_work); 1706 scsi_queue_work(shost, &rport->scan_work);
1528 1707
1708 spin_unlock_irqrestore(shost->host_lock, flags);
1709
1529 return rport; 1710 return rport;
1530 } 1711 }
1531 } 1712 }
1532 } 1713 }
1533 1714
1534 /* Search the bindings array */ 1715 /* Search the bindings array */
1535 if (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE) { 1716 if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) {
1536 1717
1537 /* search for a matching consistent binding */ 1718 /* search for a matching consistent binding */
1538 1719
1539 list_for_each_entry(rport, &fc_host_rport_bindings(shost), 1720 list_for_each_entry(rport, &fc_host->rport_bindings,
1540 peers) { 1721 peers) {
1541 if (rport->channel != channel) 1722 if (rport->channel != channel)
1542 continue; 1723 continue;
1543 1724
1544 switch (fc_host_tgtid_bind_type(shost)) { 1725 switch (fc_host->tgtid_bind_type) {
1545 case FC_TGTID_BIND_BY_WWPN: 1726 case FC_TGTID_BIND_BY_WWPN:
1546 if (rport->port_name == ids->port_name) 1727 if (rport->port_name == ids->port_name)
1547 match = 1; 1728 match = 1;
@@ -1559,8 +1740,7 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1559 } 1740 }
1560 1741
1561 if (match) { 1742 if (match) {
1562 list_move_tail(&rport->peers, 1743 list_move_tail(&rport->peers, &fc_host->rports);
1563 &fc_host_rports(shost));
1564 break; 1744 break;
1565 } 1745 }
1566 } 1746 }
@@ -1574,15 +1754,17 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1574 rport->roles = ids->roles; 1754 rport->roles = ids->roles;
1575 rport->port_state = FC_PORTSTATE_ONLINE; 1755 rport->port_state = FC_PORTSTATE_ONLINE;
1576 1756
1577 spin_unlock_irqrestore(shost->host_lock, flags);
1578
1579 if (fci->f->dd_fcrport_size) 1757 if (fci->f->dd_fcrport_size)
1580 memset(rport->dd_data, 0, 1758 memset(rport->dd_data, 0,
1581 fci->f->dd_fcrport_size); 1759 fci->f->dd_fcrport_size);
1582 1760
1583 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) 1761 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) {
1584 /* initiate a scan of the target */ 1762 /* initiate a scan of the target */
1763 rport->flags |= FC_RPORT_SCAN_PENDING;
1585 scsi_queue_work(shost, &rport->scan_work); 1764 scsi_queue_work(shost, &rport->scan_work);
1765 }
1766
1767 spin_unlock_irqrestore(shost->host_lock, flags);
1586 1768
1587 return rport; 1769 return rport;
1588 } 1770 }
@@ -1597,30 +1779,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
1597} 1779}
1598EXPORT_SYMBOL(fc_remote_port_add); 1780EXPORT_SYMBOL(fc_remote_port_add);
1599 1781
1600/*
1601 * fc_rport_terminate - this routine tears down and deallocates a remote port.
1602 * @rport: The remote port to be terminated
1603 *
1604 * Notes:
1605 * This routine assumes no locks are held on entry.
1606 */
1607static void
1608fc_rport_terminate(struct fc_rport *rport)
1609{
1610 struct Scsi_Host *shost = rport_to_shost(rport);
1611 struct device *dev = &rport->dev;
1612 unsigned long flags;
1613
1614 fc_rport_tgt_remove(rport);
1615
1616 transport_remove_device(dev);
1617 device_del(dev);
1618 transport_destroy_device(dev);
1619 spin_lock_irqsave(shost->host_lock, flags);
1620 list_del(&rport->peers);
1621 spin_unlock_irqrestore(shost->host_lock, flags);
1622 put_device(&shost->shost_gendev);
1623}
1624 1782
1625/** 1783/**
1626 * fc_remote_port_delete - notifies the fc transport that a remote 1784 * fc_remote_port_delete - notifies the fc transport that a remote
@@ -1675,20 +1833,39 @@ fc_rport_terminate(struct fc_rport *rport)
1675void 1833void
1676fc_remote_port_delete(struct fc_rport *rport) 1834fc_remote_port_delete(struct fc_rport *rport)
1677{ 1835{
1836 struct Scsi_Host *shost = rport_to_shost(rport);
1678 int timeout = rport->dev_loss_tmo; 1837 int timeout = rport->dev_loss_tmo;
1838 unsigned long flags;
1839
1840 /*
1841 * No need to flush the fc_host work_q's, as all adds are synchronous.
1842 *
1843 * We do need to reclaim the rport scan work element, so eventually
1844 * (in fc_rport_final_delete()) we'll flush the scsi host work_q if
1845 * there's still a scan pending.
1846 */
1847
1848 spin_lock_irqsave(shost->host_lock, flags);
1679 1849
1680 /* If no scsi target id mapping, delete it */ 1850 /* If no scsi target id mapping, delete it */
1681 if (rport->scsi_target_id == -1) { 1851 if (rport->scsi_target_id == -1) {
1682 fc_rport_terminate(rport); 1852 list_del(&rport->peers);
1853 rport->port_state = FC_PORTSTATE_DELETED;
1854 fc_queue_work(shost, &rport->rport_delete_work);
1855 spin_unlock_irqrestore(shost->host_lock, flags);
1683 return; 1856 return;
1684 } 1857 }
1685 1858
1859 rport->port_state = FC_PORTSTATE_BLOCKED;
1860
1861 rport->flags |= FC_RPORT_DEVLOSS_PENDING;
1862
1863 spin_unlock_irqrestore(shost->host_lock, flags);
1864
1686 scsi_target_block(&rport->dev); 1865 scsi_target_block(&rport->dev);
1687 1866
1688 /* cap the length the devices can be blocked until they are deleted */ 1867 /* cap the length the devices can be blocked until they are deleted */
1689 schedule_delayed_work(&rport->dev_loss_work, timeout * HZ); 1868 fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
1690
1691 rport->port_state = FC_PORTSTATE_BLOCKED;
1692} 1869}
1693EXPORT_SYMBOL(fc_remote_port_delete); 1870EXPORT_SYMBOL(fc_remote_port_delete);
1694 1871
@@ -1716,8 +1893,7 @@ void
1716fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) 1893fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
1717{ 1894{
1718 struct Scsi_Host *shost = rport_to_shost(rport); 1895 struct Scsi_Host *shost = rport_to_shost(rport);
1719 struct fc_host_attrs *fc_host = 1896 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1720 (struct fc_host_attrs *)shost->shost_data;
1721 unsigned long flags; 1897 unsigned long flags;
1722 int create = 0; 1898 int create = 0;
1723 1899
@@ -1729,10 +1905,11 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
1729 } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) 1905 } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET))
1730 create = 1; 1906 create = 1;
1731 } 1907 }
1732 spin_unlock_irqrestore(shost->host_lock, flags);
1733 1908
1734 rport->roles = roles; 1909 rport->roles = roles;
1735 1910
1911 spin_unlock_irqrestore(shost->host_lock, flags);
1912
1736 if (create) { 1913 if (create) {
1737 /* 1914 /*
1738 * There may have been a delete timer running on the 1915 * There may have been a delete timer running on the
@@ -1747,10 +1924,20 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
1747 * transaction. 1924 * transaction.
1748 */ 1925 */
1749 if (!cancel_delayed_work(&rport->dev_loss_work)) 1926 if (!cancel_delayed_work(&rport->dev_loss_work))
1750 flush_scheduled_work(); 1927 fc_flush_devloss(shost);
1928
1929 spin_lock_irqsave(shost->host_lock, flags);
1930 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
1931 spin_unlock_irqrestore(shost->host_lock, flags);
1932
1933 /* ensure any stgt delete functions are done */
1934 fc_flush_work(shost);
1751 1935
1752 /* initiate a scan of the target */ 1936 /* initiate a scan of the target */
1937 spin_lock_irqsave(shost->host_lock, flags);
1938 rport->flags |= FC_RPORT_SCAN_PENDING;
1753 scsi_queue_work(shost, &rport->scan_work); 1939 scsi_queue_work(shost, &rport->scan_work);
1940 spin_unlock_irqrestore(shost->host_lock, flags);
1754 } 1941 }
1755} 1942}
1756EXPORT_SYMBOL(fc_remote_port_rolechg); 1943EXPORT_SYMBOL(fc_remote_port_rolechg);
@@ -1767,22 +1954,24 @@ fc_timeout_deleted_rport(void *data)
1767{ 1954{
1768 struct fc_rport *rport = (struct fc_rport *)data; 1955 struct fc_rport *rport = (struct fc_rport *)data;
1769 struct Scsi_Host *shost = rport_to_shost(rport); 1956 struct Scsi_Host *shost = rport_to_shost(rport);
1957 struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
1770 unsigned long flags; 1958 unsigned long flags;
1771 1959
1772 spin_lock_irqsave(shost->host_lock, flags); 1960 spin_lock_irqsave(shost->host_lock, flags);
1773 1961
1962 rport->flags &= ~FC_RPORT_DEVLOSS_PENDING;
1963
1774 /* 1964 /*
1775 * If the port is ONLINE, then it came back, but was no longer an 1965 * If the port is ONLINE, then it came back. Validate it's still an
1776 * FCP target. Thus we need to tear down the scsi_target on it. 1966 * FCP target. If not, tear down the scsi_target on it.
1777 */ 1967 */
1778 if (rport->port_state == FC_PORTSTATE_ONLINE) { 1968 if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
1779 spin_unlock_irqrestore(shost->host_lock, flags); 1969 !(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
1780
1781 dev_printk(KERN_ERR, &rport->dev, 1970 dev_printk(KERN_ERR, &rport->dev,
1782 "blocked FC remote port time out: removing target\n"); 1971 "blocked FC remote port time out: no longer"
1783 1972 " a FCP target, removing starget\n");
1784 fc_rport_tgt_remove(rport); 1973 fc_queue_work(shost, &rport->stgt_delete_work);
1785 1974 spin_unlock_irqrestore(shost->host_lock, flags);
1786 return; 1975 return;
1787 } 1976 }
1788 1977
@@ -1793,11 +1982,13 @@ fc_timeout_deleted_rport(void *data)
1793 return; 1982 return;
1794 } 1983 }
1795 1984
1796 if (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE) { 1985 if (fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) {
1797 spin_unlock_irqrestore(shost->host_lock, flags); 1986 list_del(&rport->peers);
1987 rport->port_state = FC_PORTSTATE_DELETED;
1798 dev_printk(KERN_ERR, &rport->dev, 1988 dev_printk(KERN_ERR, &rport->dev,
1799 "blocked FC remote port time out: removing target\n"); 1989 "blocked FC remote port time out: removing target\n");
1800 fc_rport_terminate(rport); 1990 fc_queue_work(shost, &rport->rport_delete_work);
1991 spin_unlock_irqrestore(shost->host_lock, flags);
1801 return; 1992 return;
1802 } 1993 }
1803 1994
@@ -1805,7 +1996,7 @@ fc_timeout_deleted_rport(void *data)
1805 "blocked FC remote port time out: removing target and " 1996 "blocked FC remote port time out: removing target and "
1806 "saving binding\n"); 1997 "saving binding\n");
1807 1998
1808 list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); 1999 list_move_tail(&rport->peers, &fc_host->rport_bindings);
1809 2000
1810 /* 2001 /*
1811 * Note: We do not remove or clear the hostdata area. This allows 2002 * Note: We do not remove or clear the hostdata area. This allows
@@ -1819,10 +2010,10 @@ fc_timeout_deleted_rport(void *data)
1819 rport->maxframe_size = -1; 2010 rport->maxframe_size = -1;
1820 rport->supported_classes = FC_COS_UNSPECIFIED; 2011 rport->supported_classes = FC_COS_UNSPECIFIED;
1821 rport->roles = FC_RPORT_ROLE_UNKNOWN; 2012 rport->roles = FC_RPORT_ROLE_UNKNOWN;
1822 rport->port_state = FC_PORTSTATE_DELETED; 2013 rport->port_state = FC_PORTSTATE_NOTPRESENT;
1823 2014
1824 /* remove the identifiers that aren't used in the consisting binding */ 2015 /* remove the identifiers that aren't used in the consisting binding */
1825 switch (fc_host_tgtid_bind_type(shost)) { 2016 switch (fc_host->tgtid_bind_type) {
1826 case FC_TGTID_BIND_BY_WWPN: 2017 case FC_TGTID_BIND_BY_WWPN:
1827 rport->node_name = -1; 2018 rport->node_name = -1;
1828 rport->port_id = -1; 2019 rport->port_id = -1;
@@ -1843,17 +2034,8 @@ fc_timeout_deleted_rport(void *data)
1843 * As this only occurs if the remote port (scsi target) 2034 * As this only occurs if the remote port (scsi target)
1844 * went away and didn't come back - we'll remove 2035 * went away and didn't come back - we'll remove
1845 * all attached scsi devices. 2036 * all attached scsi devices.
1846 *
1847 * We'll schedule the shost work item to perform the actual removal
1848 * to avoid recursion in the different flush calls if we perform
1849 * the removal in each target - and there are lots of targets
1850 * whose timeouts fire at the same time.
1851 */ 2037 */
1852 2038 fc_queue_work(shost, &rport->stgt_delete_work);
1853 if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) {
1854 fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED;
1855 scsi_queue_work(shost, &fc_host_rport_del_work(shost));
1856 }
1857 2039
1858 spin_unlock_irqrestore(shost->host_lock, flags); 2040 spin_unlock_irqrestore(shost->host_lock, flags);
1859} 2041}
@@ -1870,44 +2052,18 @@ static void
1870fc_scsi_scan_rport(void *data) 2052fc_scsi_scan_rport(void *data)
1871{ 2053{
1872 struct fc_rport *rport = (struct fc_rport *)data; 2054 struct fc_rport *rport = (struct fc_rport *)data;
1873 2055 struct Scsi_Host *shost = rport_to_shost(rport);
1874 scsi_target_unblock(&rport->dev);
1875 scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id,
1876 SCAN_WILD_CARD, 1);
1877}
1878
1879
1880/**
1881 * fc_shost_remove_rports - called to remove all rports that are marked
1882 * as in a deleted (not connected) state.
1883 *
1884 * @data: shost whose rports are to be looked at
1885 **/
1886static void
1887fc_shost_remove_rports(void *data)
1888{
1889 struct Scsi_Host *shost = (struct Scsi_Host *)data;
1890 struct fc_rport *rport, *next_rport;
1891 unsigned long flags; 2056 unsigned long flags;
1892 2057
1893 spin_lock_irqsave(shost->host_lock, flags); 2058 if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
1894 while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { 2059 (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
1895 2060 scsi_target_unblock(&rport->dev);
1896 fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; 2061 scsi_scan_target(&rport->dev, rport->channel,
1897 2062 rport->scsi_target_id, SCAN_WILD_CARD, 1);
1898restart_search:
1899 list_for_each_entry_safe(rport, next_rport,
1900 &fc_host_rport_bindings(shost), peers) {
1901 if (rport->port_state == FC_PORTSTATE_DELETED) {
1902 rport->port_state = FC_PORTSTATE_NOTPRESENT;
1903 spin_unlock_irqrestore(shost->host_lock, flags);
1904 fc_rport_tgt_remove(rport);
1905 spin_lock_irqsave(shost->host_lock, flags);
1906 goto restart_search;
1907 }
1908 }
1909
1910 } 2063 }
2064
2065 spin_lock_irqsave(shost->host_lock, flags);
2066 rport->flags &= ~FC_RPORT_SCAN_PENDING;
1911 spin_unlock_irqrestore(shost->host_lock, flags); 2067 spin_unlock_irqrestore(shost->host_lock, flags);
1912} 2068}
1913 2069