diff options
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 466 | ||||
| -rw-r--r-- | include/scsi/scsi_transport_fc.h | 41 |
2 files changed, 341 insertions, 166 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 | ||
| 37 | static 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 | ||
| 216 | static void fc_shost_remove_rports(void *data); | ||
| 217 | static void fc_timeout_deleted_rport(void *data); | 218 | static void fc_timeout_deleted_rport(void *data); |
| 218 | static void fc_scsi_scan_rport(void *data); | 219 | static void fc_scsi_scan_rport(void *data); |
| 219 | static 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 | } |
| 1263 | EXPORT_SYMBOL(fc_release_transport); | 1279 | EXPORT_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 | **/ | ||
| 1289 | static int | ||
| 1290 | fc_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 | **/ | ||
| 1308 | static void | ||
| 1309 | fc_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 | **/ | ||
| 1331 | static int | ||
| 1332 | fc_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 | **/ | ||
| 1351 | static void | ||
| 1352 | fc_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 | |||
| 1283 | fc_remove_host(struct Scsi_Host *shost) | 1383 | fc_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 | } |
| 1295 | EXPORT_SYMBOL(fc_remove_host); | 1421 | EXPORT_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 | **/ | ||
| 1301 | static void | 1430 | static void |
| 1302 | fc_rport_tgt_remove(struct fc_rport *rport) | 1431 | fc_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 | **/ | ||
| 1458 | static void | ||
| 1459 | fc_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 * | |||
| 1330 | fc_rport_create(struct Scsi_Host *shost, int channel, | 1497 | fc_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 | } |
| 1598 | EXPORT_SYMBOL(fc_remote_port_add); | 1780 | EXPORT_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 | */ | ||
| 1607 | static void | ||
| 1608 | fc_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) | |||
| 1675 | void | 1833 | void |
| 1676 | fc_remote_port_delete(struct fc_rport *rport) | 1834 | fc_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 | } |
| 1693 | EXPORT_SYMBOL(fc_remote_port_delete); | 1870 | EXPORT_SYMBOL(fc_remote_port_delete); |
| 1694 | 1871 | ||
| @@ -1716,8 +1893,7 @@ void | |||
| 1716 | fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) | 1893 | fc_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 | } |
| 1756 | EXPORT_SYMBOL(fc_remote_port_rolechg); | 1943 | EXPORT_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 | |||
| 1870 | fc_scsi_scan_rport(void *data) | 2052 | fc_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 | **/ | ||
| 1886 | static void | ||
| 1887 | fc_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); | |
| 1898 | restart_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 | ||
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index cf3fec8be1e3..5626225bd3ae 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h | |||
| @@ -202,12 +202,19 @@ struct fc_rport { /* aka fc_starget_attrs */ | |||
| 202 | /* internal data */ | 202 | /* internal data */ |
| 203 | unsigned int channel; | 203 | unsigned int channel; |
| 204 | u32 number; | 204 | u32 number; |
| 205 | u8 flags; | ||
| 205 | struct list_head peers; | 206 | struct list_head peers; |
| 206 | struct device dev; | 207 | struct device dev; |
| 207 | struct work_struct dev_loss_work; | 208 | struct work_struct dev_loss_work; |
| 208 | struct work_struct scan_work; | 209 | struct work_struct scan_work; |
| 210 | struct work_struct stgt_delete_work; | ||
| 211 | struct work_struct rport_delete_work; | ||
| 209 | } __attribute__((aligned(sizeof(unsigned long)))); | 212 | } __attribute__((aligned(sizeof(unsigned long)))); |
| 210 | 213 | ||
| 214 | /* bit field values for struct fc_rport "flags" field: */ | ||
| 215 | #define FC_RPORT_DEVLOSS_PENDING 0x01 | ||
| 216 | #define FC_RPORT_SCAN_PENDING 0x02 | ||
| 217 | |||
| 211 | #define dev_to_rport(d) \ | 218 | #define dev_to_rport(d) \ |
| 212 | container_of(d, struct fc_rport, dev) | 219 | container_of(d, struct fc_rport, dev) |
| 213 | #define transport_class_to_rport(classdev) \ | 220 | #define transport_class_to_rport(classdev) \ |
| @@ -327,13 +334,16 @@ struct fc_host_attrs { | |||
| 327 | struct list_head rport_bindings; | 334 | struct list_head rport_bindings; |
| 328 | u32 next_rport_number; | 335 | u32 next_rport_number; |
| 329 | u32 next_target_id; | 336 | u32 next_target_id; |
| 330 | u8 flags; | ||
| 331 | struct work_struct rport_del_work; | ||
| 332 | }; | ||
| 333 | 337 | ||
| 334 | /* values for struct fc_host_attrs "flags" field: */ | 338 | /* work queues for rport state manipulation */ |
| 335 | #define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 | 339 | char work_q_name[KOBJ_NAME_LEN]; |
| 340 | struct workqueue_struct *work_q; | ||
| 341 | char devloss_work_q_name[KOBJ_NAME_LEN]; | ||
| 342 | struct workqueue_struct *devloss_work_q; | ||
| 343 | }; | ||
| 336 | 344 | ||
| 345 | #define shost_to_fc_host(x) \ | ||
| 346 | ((struct fc_host_attrs *)(x)->shost_data) | ||
| 337 | 347 | ||
| 338 | #define fc_host_node_name(x) \ | 348 | #define fc_host_node_name(x) \ |
| 339 | (((struct fc_host_attrs *)(x)->shost_data)->node_name) | 349 | (((struct fc_host_attrs *)(x)->shost_data)->node_name) |
| @@ -375,10 +385,14 @@ struct fc_host_attrs { | |||
| 375 | (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) | 385 | (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) |
| 376 | #define fc_host_next_target_id(x) \ | 386 | #define fc_host_next_target_id(x) \ |
| 377 | (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) | 387 | (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) |
| 378 | #define fc_host_flags(x) \ | 388 | #define fc_host_work_q_name(x) \ |
| 379 | (((struct fc_host_attrs *)(x)->shost_data)->flags) | 389 | (((struct fc_host_attrs *)(x)->shost_data)->work_q_name) |
| 380 | #define fc_host_rport_del_work(x) \ | 390 | #define fc_host_work_q(x) \ |
| 381 | (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) | 391 | (((struct fc_host_attrs *)(x)->shost_data)->work_q) |
| 392 | #define fc_host_devloss_work_q_name(x) \ | ||
| 393 | (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name) | ||
| 394 | #define fc_host_devloss_work_q(x) \ | ||
| 395 | (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q) | ||
| 382 | 396 | ||
| 383 | 397 | ||
| 384 | /* The functions by which the transport class and the driver communicate */ | 398 | /* The functions by which the transport class and the driver communicate */ |
| @@ -461,10 +475,15 @@ fc_remote_port_chkready(struct fc_rport *rport) | |||
| 461 | 475 | ||
| 462 | switch (rport->port_state) { | 476 | switch (rport->port_state) { |
| 463 | case FC_PORTSTATE_ONLINE: | 477 | case FC_PORTSTATE_ONLINE: |
| 464 | result = 0; | 478 | if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) |
| 479 | result = 0; | ||
| 480 | else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) | ||
| 481 | result = DID_IMM_RETRY << 16; | ||
| 482 | else | ||
| 483 | result = DID_NO_CONNECT << 16; | ||
| 465 | break; | 484 | break; |
| 466 | case FC_PORTSTATE_BLOCKED: | 485 | case FC_PORTSTATE_BLOCKED: |
| 467 | result = DID_BUS_BUSY << 16; | 486 | result = DID_IMM_RETRY << 16; |
| 468 | break; | 487 | break; |
| 469 | default: | 488 | default: |
| 470 | result = DID_NO_CONNECT << 16; | 489 | result = DID_NO_CONNECT << 16; |
