diff options
author | James Bottomley <jejb@titanic.(none)> | 2005-11-04 23:29:52 -0500 |
---|---|---|
committer | James Bottomley <jejb@titanic.(none)> | 2005-11-04 23:29:52 -0500 |
commit | 849a8924a6740ecbf9711e015beca69425f0c429 (patch) | |
tree | 2bae44c5fb170a655696b7253eec7ee13c6fa437 /drivers/scsi/scsi_transport_fc.c | |
parent | 7015faa7df829876a0f931cd18aa6d7c24a1b581 (diff) | |
parent | ee807c2d43b54183c16580857837dae8ccb2ed22 (diff) |
Merge by Hand
Conflicts in dec_esp.c (Thanks Bacchus), scsi_transport_iscsi.c and
scsi_transport_fc.h
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/scsi_transport_fc.c')
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 476 |
1 files changed, 304 insertions, 172 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index b856e140e65f..6cd5931d9a54 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -33,8 +33,6 @@ | |||
33 | #include <scsi/scsi_transport_fc.h> | 33 | #include <scsi/scsi_transport_fc.h> |
34 | #include "scsi_priv.h" | 34 | #include "scsi_priv.h" |
35 | 35 | ||
36 | #define FC_PRINTK(x, l, f, a...) printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a) | ||
37 | |||
38 | /* | 36 | /* |
39 | * Redefine so that we can have same named attributes in the | 37 | * Redefine so that we can have same named attributes in the |
40 | * sdev/starget/host objects. | 38 | * sdev/starget/host objects. |
@@ -213,7 +211,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) | |||
213 | #define FC_MGMTSRVR_PORTID 0x00000a | 211 | #define FC_MGMTSRVR_PORTID 0x00000a |
214 | 212 | ||
215 | 213 | ||
216 | static void fc_timeout_blocked_rport(void *data); | 214 | static void fc_timeout_deleted_rport(void *data); |
217 | static void fc_scsi_scan_rport(void *data); | 215 | static void fc_scsi_scan_rport(void *data); |
218 | static void fc_rport_terminate(struct fc_rport *rport); | 216 | static void fc_rport_terminate(struct fc_rport *rport); |
219 | 217 | ||
@@ -223,7 +221,7 @@ static void fc_rport_terminate(struct fc_rport *rport); | |||
223 | */ | 221 | */ |
224 | #define FC_STARGET_NUM_ATTRS 3 | 222 | #define FC_STARGET_NUM_ATTRS 3 |
225 | #define FC_RPORT_NUM_ATTRS 9 | 223 | #define FC_RPORT_NUM_ATTRS 9 |
226 | #define FC_HOST_NUM_ATTRS 15 | 224 | #define FC_HOST_NUM_ATTRS 16 |
227 | 225 | ||
228 | struct fc_internal { | 226 | struct fc_internal { |
229 | struct scsi_transport_template t; | 227 | struct scsi_transport_template t; |
@@ -387,7 +385,9 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ | |||
387 | struct fc_rport *rport = transport_class_to_rport(cdev); \ | 385 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
388 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 386 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
389 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 387 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
390 | if (i->f->get_rport_##field) \ | 388 | if ((i->f->get_rport_##field) && \ |
389 | !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | ||
390 | (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ | ||
391 | i->f->get_rport_##field(rport); \ | 391 | i->f->get_rport_##field(rport); \ |
392 | return snprintf(buf, sz, format_string, cast rport->field); \ | 392 | return snprintf(buf, sz, format_string, cast rport->field); \ |
393 | } | 393 | } |
@@ -401,6 +401,9 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ | |||
401 | struct fc_rport *rport = transport_class_to_rport(cdev); \ | 401 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
402 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 402 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
403 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 403 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
404 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | ||
405 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ | ||
406 | return -EBUSY; \ | ||
404 | val = simple_strtoul(buf, NULL, 0); \ | 407 | val = simple_strtoul(buf, NULL, 0); \ |
405 | i->f->set_rport_##field(rport, val); \ | 408 | i->f->set_rport_##field(rport, val); \ |
406 | return count; \ | 409 | return count; \ |
@@ -503,7 +506,29 @@ static FC_CLASS_DEVICE_ATTR(rport, supported_classes, S_IRUGO, | |||
503 | 506 | ||
504 | /* Dynamic Remote Port Attributes */ | 507 | /* Dynamic Remote Port Attributes */ |
505 | 508 | ||
506 | fc_rport_rw_attr(dev_loss_tmo, "%d\n", 20); | 509 | /* |
510 | * dev_loss_tmo attribute | ||
511 | */ | ||
512 | fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) | ||
513 | static ssize_t | ||
514 | store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, | ||
515 | size_t count) | ||
516 | { | ||
517 | int val; | ||
518 | struct fc_rport *rport = transport_class_to_rport(cdev); | ||
519 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
520 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
521 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | ||
522 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | ||
523 | return -EBUSY; | ||
524 | val = simple_strtoul(buf, NULL, 0); | ||
525 | if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | ||
526 | return -EINVAL; | ||
527 | i->f->set_rport_dev_loss_tmo(rport, val); | ||
528 | return count; | ||
529 | } | ||
530 | static FC_CLASS_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, | ||
531 | show_fc_rport_dev_loss_tmo, store_fc_rport_dev_loss_tmo); | ||
507 | 532 | ||
508 | 533 | ||
509 | /* Private Remote Port Attributes */ | 534 | /* Private Remote Port Attributes */ |
@@ -716,9 +741,11 @@ static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \ | |||
716 | count++ | 741 | count++ |
717 | 742 | ||
718 | #define SETUP_PRIVATE_HOST_ATTRIBUTE_RW(field) \ | 743 | #define SETUP_PRIVATE_HOST_ATTRIBUTE_RW(field) \ |
744 | { \ | ||
719 | i->private_host_attrs[count] = class_device_attr_host_##field; \ | 745 | i->private_host_attrs[count] = class_device_attr_host_##field; \ |
720 | i->host_attrs[count] = &i->private_host_attrs[count]; \ | 746 | i->host_attrs[count] = &i->private_host_attrs[count]; \ |
721 | count++ | 747 | count++; \ |
748 | } | ||
722 | 749 | ||
723 | 750 | ||
724 | /* Fixed Host Attributes */ | 751 | /* Fixed Host Attributes */ |
@@ -856,6 +883,26 @@ static FC_CLASS_DEVICE_ATTR(host, tgtid_bind_type, S_IRUGO | S_IWUSR, | |||
856 | show_fc_private_host_tgtid_bind_type, | 883 | show_fc_private_host_tgtid_bind_type, |
857 | store_fc_private_host_tgtid_bind_type); | 884 | store_fc_private_host_tgtid_bind_type); |
858 | 885 | ||
886 | static ssize_t | ||
887 | store_fc_private_host_issue_lip(struct class_device *cdev, | ||
888 | const char *buf, size_t count) | ||
889 | { | ||
890 | struct Scsi_Host *shost = transport_class_to_shost(cdev); | ||
891 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
892 | int ret; | ||
893 | |||
894 | /* ignore any data value written to the attribute */ | ||
895 | if (i->f->issue_fc_host_lip) { | ||
896 | ret = i->f->issue_fc_host_lip(shost); | ||
897 | return ret ? ret: count; | ||
898 | } | ||
899 | |||
900 | return -ENOENT; | ||
901 | } | ||
902 | |||
903 | static FC_CLASS_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, | ||
904 | store_fc_private_host_issue_lip); | ||
905 | |||
859 | /* | 906 | /* |
860 | * Host Statistics Management | 907 | * Host Statistics Management |
861 | */ | 908 | */ |
@@ -1122,6 +1169,8 @@ fc_attach_transport(struct fc_function_template *ft) | |||
1122 | 1169 | ||
1123 | /* Transport-managed attributes */ | 1170 | /* Transport-managed attributes */ |
1124 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); | 1171 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); |
1172 | if (ft->issue_fc_host_lip) | ||
1173 | SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); | ||
1125 | 1174 | ||
1126 | BUG_ON(count > FC_HOST_NUM_ATTRS); | 1175 | BUG_ON(count > FC_HOST_NUM_ATTRS); |
1127 | 1176 | ||
@@ -1193,6 +1242,25 @@ fc_remove_host(struct Scsi_Host *shost) | |||
1193 | } | 1242 | } |
1194 | EXPORT_SYMBOL(fc_remove_host); | 1243 | EXPORT_SYMBOL(fc_remove_host); |
1195 | 1244 | ||
1245 | /* | ||
1246 | * fc_rport_tgt_remove - Removes the scsi target on the remote port | ||
1247 | * @rport: The remote port to be operated on | ||
1248 | */ | ||
1249 | static void | ||
1250 | fc_rport_tgt_remove(struct fc_rport *rport) | ||
1251 | { | ||
1252 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
1253 | |||
1254 | scsi_target_unblock(&rport->dev); | ||
1255 | |||
1256 | /* Stop anything on the workq */ | ||
1257 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
1258 | flush_scheduled_work(); | ||
1259 | scsi_flush_work(shost); | ||
1260 | |||
1261 | scsi_remove_target(&rport->dev); | ||
1262 | } | ||
1263 | |||
1196 | /** | 1264 | /** |
1197 | * fc_rport_create - allocates and creates a remote FC port. | 1265 | * fc_rport_create - allocates and creates a remote FC port. |
1198 | * @shost: scsi host the remote port is connected to. | 1266 | * @shost: scsi host the remote port is connected to. |
@@ -1239,7 +1307,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
1239 | rport->dd_data = &rport[1]; | 1307 | rport->dd_data = &rport[1]; |
1240 | rport->channel = channel; | 1308 | rport->channel = channel; |
1241 | 1309 | ||
1242 | INIT_WORK(&rport->dev_loss_work, fc_timeout_blocked_rport, rport); | 1310 | INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); |
1243 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); | 1311 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); |
1244 | 1312 | ||
1245 | spin_lock_irqsave(shost->host_lock, flags); | 1313 | spin_lock_irqsave(shost->host_lock, flags); |
@@ -1331,17 +1399,93 @@ struct fc_rport * | |||
1331 | fc_remote_port_add(struct Scsi_Host *shost, int channel, | 1399 | fc_remote_port_add(struct Scsi_Host *shost, int channel, |
1332 | struct fc_rport_identifiers *ids) | 1400 | struct fc_rport_identifiers *ids) |
1333 | { | 1401 | { |
1402 | struct fc_internal *fci = to_fc_internal(shost->transportt); | ||
1334 | struct fc_rport *rport; | 1403 | struct fc_rport *rport; |
1335 | unsigned long flags; | 1404 | unsigned long flags; |
1336 | int match = 0; | 1405 | int match = 0; |
1337 | 1406 | ||
1407 | /* | ||
1408 | * Search the list of "active" rports, for an rport that has been | ||
1409 | * deleted, but we've held off the real delete while the target | ||
1410 | * is in a "blocked" state. | ||
1411 | */ | ||
1412 | spin_lock_irqsave(shost->host_lock, flags); | ||
1413 | |||
1414 | list_for_each_entry(rport, &fc_host_rports(shost), peers) { | ||
1415 | |||
1416 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) && | ||
1417 | (rport->channel == channel)) { | ||
1418 | |||
1419 | switch (fc_host_tgtid_bind_type(shost)) { | ||
1420 | case FC_TGTID_BIND_BY_WWPN: | ||
1421 | case FC_TGTID_BIND_NONE: | ||
1422 | if (rport->port_name == ids->port_name) | ||
1423 | match = 1; | ||
1424 | break; | ||
1425 | case FC_TGTID_BIND_BY_WWNN: | ||
1426 | if (rport->node_name == ids->node_name) | ||
1427 | match = 1; | ||
1428 | break; | ||
1429 | case FC_TGTID_BIND_BY_ID: | ||
1430 | if (rport->port_id == ids->port_id) | ||
1431 | match = 1; | ||
1432 | break; | ||
1433 | } | ||
1434 | |||
1435 | if (match) { | ||
1436 | struct work_struct *work = | ||
1437 | &rport->dev_loss_work; | ||
1438 | |||
1439 | memcpy(&rport->node_name, &ids->node_name, | ||
1440 | sizeof(rport->node_name)); | ||
1441 | memcpy(&rport->port_name, &ids->port_name, | ||
1442 | sizeof(rport->port_name)); | ||
1443 | rport->port_id = ids->port_id; | ||
1444 | |||
1445 | rport->port_state = FC_PORTSTATE_ONLINE; | ||
1446 | rport->roles = ids->roles; | ||
1447 | |||
1448 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1449 | |||
1450 | if (fci->f->dd_fcrport_size) | ||
1451 | memset(rport->dd_data, 0, | ||
1452 | fci->f->dd_fcrport_size); | ||
1453 | |||
1454 | /* | ||
1455 | * If we were blocked, we were a target. | ||
1456 | * If no longer a target, we leave the timer | ||
1457 | * running in case the port changes roles | ||
1458 | * prior to the timer expiring. If the timer | ||
1459 | * fires, the target will be torn down. | ||
1460 | */ | ||
1461 | if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)) | ||
1462 | return rport; | ||
1463 | |||
1464 | /* restart the target */ | ||
1465 | |||
1466 | /* | ||
1467 | * Stop the target timer first. Take no action | ||
1468 | * on the del_timer failure as the state | ||
1469 | * machine state change will validate the | ||
1470 | * transaction. | ||
1471 | */ | ||
1472 | if (!cancel_delayed_work(work)) | ||
1473 | flush_scheduled_work(); | ||
1474 | |||
1475 | /* initiate a scan of the target */ | ||
1476 | scsi_queue_work(shost, &rport->scan_work); | ||
1477 | |||
1478 | return rport; | ||
1479 | } | ||
1480 | } | ||
1481 | } | ||
1482 | |||
1483 | /* Search the bindings array */ | ||
1338 | if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) && | 1484 | if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) && |
1339 | (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) { | 1485 | (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) { |
1340 | 1486 | ||
1341 | /* search for a matching consistent binding */ | 1487 | /* search for a matching consistent binding */ |
1342 | 1488 | ||
1343 | spin_lock_irqsave(shost->host_lock, flags); | ||
1344 | |||
1345 | list_for_each_entry(rport, &fc_host_rport_bindings(shost), | 1489 | list_for_each_entry(rport, &fc_host_rport_bindings(shost), |
1346 | peers) { | 1490 | peers) { |
1347 | if (rport->channel != channel) | 1491 | if (rport->channel != channel) |
@@ -1371,8 +1515,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
1371 | } | 1515 | } |
1372 | } | 1516 | } |
1373 | 1517 | ||
1374 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1375 | |||
1376 | if (match) { | 1518 | if (match) { |
1377 | memcpy(&rport->node_name, &ids->node_name, | 1519 | memcpy(&rport->node_name, &ids->node_name, |
1378 | sizeof(rport->node_name)); | 1520 | sizeof(rport->node_name)); |
@@ -1382,6 +1524,12 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
1382 | rport->roles = ids->roles; | 1524 | rport->roles = ids->roles; |
1383 | rport->port_state = FC_PORTSTATE_ONLINE; | 1525 | rport->port_state = FC_PORTSTATE_ONLINE; |
1384 | 1526 | ||
1527 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1528 | |||
1529 | if (fci->f->dd_fcrport_size) | ||
1530 | memset(rport->dd_data, 0, | ||
1531 | fci->f->dd_fcrport_size); | ||
1532 | |||
1385 | if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) | 1533 | if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) |
1386 | /* initiate a scan of the target */ | 1534 | /* initiate a scan of the target */ |
1387 | scsi_queue_work(shost, &rport->scan_work); | 1535 | scsi_queue_work(shost, &rport->scan_work); |
@@ -1390,6 +1538,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
1390 | } | 1538 | } |
1391 | } | 1539 | } |
1392 | 1540 | ||
1541 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1542 | |||
1393 | /* No consistent binding found - create new remote port entry */ | 1543 | /* No consistent binding found - create new remote port entry */ |
1394 | rport = fc_rport_create(shost, channel, ids); | 1544 | rport = fc_rport_create(shost, channel, ids); |
1395 | 1545 | ||
@@ -1398,25 +1548,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
1398 | EXPORT_SYMBOL(fc_remote_port_add); | 1548 | EXPORT_SYMBOL(fc_remote_port_add); |
1399 | 1549 | ||
1400 | /* | 1550 | /* |
1401 | * fc_rport_tgt_remove - Removes the scsi target on the remote port | ||
1402 | * @rport: The remote port to be operated on | ||
1403 | */ | ||
1404 | static void | ||
1405 | fc_rport_tgt_remove(struct fc_rport *rport) | ||
1406 | { | ||
1407 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
1408 | |||
1409 | scsi_target_unblock(&rport->dev); | ||
1410 | |||
1411 | /* Stop anything on the workq */ | ||
1412 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
1413 | flush_scheduled_work(); | ||
1414 | scsi_flush_work(shost); | ||
1415 | |||
1416 | scsi_remove_target(&rport->dev); | ||
1417 | } | ||
1418 | |||
1419 | /* | ||
1420 | * fc_rport_terminate - this routine tears down and deallocates a remote port. | 1551 | * fc_rport_terminate - this routine tears down and deallocates a remote port. |
1421 | * @rport: The remote port to be terminated | 1552 | * @rport: The remote port to be terminated |
1422 | * | 1553 | * |
@@ -1449,24 +1580,44 @@ fc_rport_terminate(struct fc_rport *rport) | |||
1449 | * The LLDD calls this routine to notify the transport that a remote | 1580 | * The LLDD calls this routine to notify the transport that a remote |
1450 | * port is no longer part of the topology. Note: Although a port | 1581 | * port is no longer part of the topology. Note: Although a port |
1451 | * may no longer be part of the topology, it may persist in the remote | 1582 | * may no longer be part of the topology, it may persist in the remote |
1452 | * ports displayed by the fc_host. This is done so that target id | 1583 | * ports displayed by the fc_host. We do this under 2 conditions: |
1453 | * mappings (managed via the remote port structures), are always visible | 1584 | * - If the port was a scsi target, we delay its deletion by "blocking" it. |
1454 | * as long as the mapping is valid, regardless of port state, | 1585 | * This allows the port to temporarily disappear, then reappear without |
1586 | * disrupting the SCSI device tree attached to it. During the "blocked" | ||
1587 | * period the port will still exist. | ||
1588 | * - If the port was a scsi target and disappears for longer than we | ||
1589 | * expect, we'll delete the port and the tear down the SCSI device tree | ||
1590 | * attached to it. However, we want to semi-persist the target id assigned | ||
1591 | * to that port if it eventually does exist. The port structure will | ||
1592 | * remain (although with minimal information) so that the target id | ||
1593 | * bindings remails. | ||
1455 | * | 1594 | * |
1456 | * If the remote port is not an FCP Target, it will be fully torn down | 1595 | * If the remote port is not an FCP Target, it will be fully torn down |
1457 | * and deallocated, including the fc_remote_port class device. | 1596 | * and deallocated, including the fc_remote_port class device. |
1458 | * | 1597 | * |
1459 | * If the remote port is an FCP Target, the port structure will be | 1598 | * If the remote port is an FCP Target, the port will be placed in a |
1460 | * marked as Not Present, but will remain as long as there is a valid | 1599 | * temporary blocked state. From the LLDD's perspective, the rport no |
1461 | * SCSI target id mapping associated with the port structure. Validity | 1600 | * longer exists. From the SCSI midlayer's perspective, the SCSI target |
1462 | * is determined by the binding type. If binding by wwpn, then the port | 1601 | * exists, but all sdevs on it are blocked from further I/O. The following |
1463 | * structure is always valid and will not be deallocated until the host | 1602 | * is then expected: |
1464 | * is removed. If binding by wwnn, then the port structure is valid | 1603 | * If the remote port does not return (signaled by a LLDD call to |
1465 | * until another port with the same node name is found in the topology. | 1604 | * fc_remote_port_add()) within the dev_loss_tmo timeout, then the |
1466 | * If binding by port id (fc address), then the port structure is valid | 1605 | * scsi target is removed - killing all outstanding i/o and removing the |
1467 | * valid until another port with the same address is identified. | 1606 | * scsi devices attached ot it. The port structure will be marked Not |
1607 | * Present and be partially cleared, leaving only enough information to | ||
1608 | * recognize the remote port relative to the scsi target id binding if | ||
1609 | * it later appears. The port will remain as long as there is a valid | ||
1610 | * binding (e.g. until the user changes the binding type or unloads the | ||
1611 | * scsi host with the binding). | ||
1468 | * | 1612 | * |
1469 | * Called from interrupt or normal process context. | 1613 | * If the remote port returns within the dev_loss_tmo value (and matches |
1614 | * according to the target id binding type), the port structure will be | ||
1615 | * reused. If it is no longer a SCSI target, the target will be torn | ||
1616 | * down. If it continues to be a SCSI target, then the target will be | ||
1617 | * unblocked (allowing i/o to be resumed), and a scan will be activated | ||
1618 | * to ensure that all luns are detected. | ||
1619 | * | ||
1620 | * Called from normal process context only - cannot be called from interrupt. | ||
1470 | * | 1621 | * |
1471 | * Notes: | 1622 | * Notes: |
1472 | * This routine assumes no locks are held on entry. | 1623 | * This routine assumes no locks are held on entry. |
@@ -1474,53 +1625,20 @@ fc_rport_terminate(struct fc_rport *rport) | |||
1474 | void | 1625 | void |
1475 | fc_remote_port_delete(struct fc_rport *rport) | 1626 | fc_remote_port_delete(struct fc_rport *rport) |
1476 | { | 1627 | { |
1477 | struct Scsi_Host *shost = rport_to_shost(rport); | 1628 | int timeout = rport->dev_loss_tmo; |
1478 | unsigned long flags; | ||
1479 | 1629 | ||
1480 | /* If no scsi target id mapping or consistent binding type, delete it */ | 1630 | /* If no scsi target id mapping, delete it */ |
1481 | if ((rport->scsi_target_id == -1) || | 1631 | if (rport->scsi_target_id == -1) { |
1482 | (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE)) { | ||
1483 | fc_rport_terminate(rport); | 1632 | fc_rport_terminate(rport); |
1484 | return; | 1633 | return; |
1485 | } | 1634 | } |
1486 | 1635 | ||
1487 | fc_rport_tgt_remove(rport); | 1636 | scsi_target_block(&rport->dev); |
1488 | 1637 | ||
1489 | spin_lock_irqsave(shost->host_lock, flags); | 1638 | /* cap the length the devices can be blocked until they are deleted */ |
1490 | list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); | 1639 | schedule_delayed_work(&rport->dev_loss_work, timeout * HZ); |
1491 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1492 | 1640 | ||
1493 | /* | 1641 | rport->port_state = FC_PORTSTATE_BLOCKED; |
1494 | * Note: We do not remove or clear the hostdata area. This allows | ||
1495 | * host-specific target data to persist along with the | ||
1496 | * scsi_target_id. It's up to the host to manage it's hostdata area. | ||
1497 | */ | ||
1498 | |||
1499 | /* | ||
1500 | * Reinitialize port attributes that may change if the port comes back. | ||
1501 | */ | ||
1502 | rport->maxframe_size = -1; | ||
1503 | rport->supported_classes = FC_COS_UNSPECIFIED; | ||
1504 | rport->roles = FC_RPORT_ROLE_UNKNOWN; | ||
1505 | rport->port_state = FC_PORTSTATE_NOTPRESENT; | ||
1506 | |||
1507 | /* remove the identifiers that aren't used in the consisting binding */ | ||
1508 | switch (fc_host_tgtid_bind_type(shost)) { | ||
1509 | case FC_TGTID_BIND_BY_WWPN: | ||
1510 | rport->node_name = -1; | ||
1511 | rport->port_id = -1; | ||
1512 | break; | ||
1513 | case FC_TGTID_BIND_BY_WWNN: | ||
1514 | rport->port_name = -1; | ||
1515 | rport->port_id = -1; | ||
1516 | break; | ||
1517 | case FC_TGTID_BIND_BY_ID: | ||
1518 | rport->node_name = -1; | ||
1519 | rport->port_name = -1; | ||
1520 | break; | ||
1521 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | ||
1522 | break; | ||
1523 | } | ||
1524 | } | 1642 | } |
1525 | EXPORT_SYMBOL(fc_remote_port_delete); | 1643 | EXPORT_SYMBOL(fc_remote_port_delete); |
1526 | 1644 | ||
@@ -1553,127 +1671,140 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) | |||
1553 | unsigned long flags; | 1671 | unsigned long flags; |
1554 | int create = 0; | 1672 | int create = 0; |
1555 | 1673 | ||
1556 | rport->roles = roles; | ||
1557 | |||
1558 | spin_lock_irqsave(shost->host_lock, flags); | 1674 | spin_lock_irqsave(shost->host_lock, flags); |
1559 | if ((rport->scsi_target_id == -1) && | 1675 | if (roles & FC_RPORT_ROLE_FCP_TARGET) { |
1560 | (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { | 1676 | if (rport->scsi_target_id == -1) { |
1561 | rport->scsi_target_id = fc_host->next_target_id++; | 1677 | rport->scsi_target_id = fc_host->next_target_id++; |
1562 | create = 1; | 1678 | create = 1; |
1679 | } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) | ||
1680 | create = 1; | ||
1563 | } | 1681 | } |
1564 | spin_unlock_irqrestore(shost->host_lock, flags); | 1682 | spin_unlock_irqrestore(shost->host_lock, flags); |
1565 | 1683 | ||
1566 | if (create) | 1684 | rport->roles = roles; |
1685 | |||
1686 | if (create) { | ||
1687 | /* | ||
1688 | * There may have been a delete timer running on the | ||
1689 | * port. Ensure that it is cancelled as we now know | ||
1690 | * the port is an FCP Target. | ||
1691 | * Note: we know the rport is exists and in an online | ||
1692 | * state as the LLDD would not have had an rport | ||
1693 | * reference to pass us. | ||
1694 | * | ||
1695 | * Take no action on the del_timer failure as the state | ||
1696 | * machine state change will validate the | ||
1697 | * transaction. | ||
1698 | */ | ||
1699 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
1700 | flush_scheduled_work(); | ||
1701 | |||
1567 | /* initiate a scan of the target */ | 1702 | /* initiate a scan of the target */ |
1568 | scsi_queue_work(shost, &rport->scan_work); | 1703 | scsi_queue_work(shost, &rport->scan_work); |
1704 | } | ||
1569 | } | 1705 | } |
1570 | EXPORT_SYMBOL(fc_remote_port_rolechg); | 1706 | EXPORT_SYMBOL(fc_remote_port_rolechg); |
1571 | 1707 | ||
1572 | /** | 1708 | /** |
1573 | * fc_timeout_blocked_rport - Timeout handler for blocked remote port | 1709 | * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that |
1574 | * that fails to return in the alloted time. | 1710 | * was a SCSI target (thus was blocked), and failed |
1575 | * @data: scsi target that failed to reappear in the alloted time. | 1711 | * to return in the alloted time. |
1712 | * | ||
1713 | * @data: rport target that failed to reappear in the alloted time. | ||
1576 | **/ | 1714 | **/ |
1577 | static void | 1715 | static void |
1578 | fc_timeout_blocked_rport(void *data) | 1716 | fc_timeout_deleted_rport(void *data) |
1579 | { | 1717 | { |
1580 | struct fc_rport *rport = (struct fc_rport *)data; | 1718 | struct fc_rport *rport = (struct fc_rport *)data; |
1719 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
1720 | unsigned long flags; | ||
1581 | 1721 | ||
1582 | rport->port_state = FC_PORTSTATE_OFFLINE; | 1722 | spin_lock_irqsave(shost->host_lock, flags); |
1583 | |||
1584 | dev_printk(KERN_ERR, &rport->dev, | ||
1585 | "blocked FC remote port time out: removing target\n"); | ||
1586 | 1723 | ||
1587 | /* | 1724 | /* |
1588 | * As this only occurs if the remote port (scsi target) | 1725 | * If the port is ONLINE, then it came back, but was no longer an |
1589 | * went away and didn't come back - we'll remove | 1726 | * FCP target. Thus we need to tear down the scsi_target on it. |
1590 | * all attached scsi devices. | ||
1591 | */ | 1727 | */ |
1592 | scsi_target_unblock(&rport->dev); | 1728 | if (rport->port_state == FC_PORTSTATE_ONLINE) { |
1593 | scsi_remove_target(&rport->dev); | 1729 | spin_unlock_irqrestore(shost->host_lock, flags); |
1594 | } | ||
1595 | 1730 | ||
1596 | /** | 1731 | dev_printk(KERN_ERR, &rport->dev, |
1597 | * fc_remote_port_block - temporarily block any scsi traffic to a remote port. | 1732 | "blocked FC remote port time out: removing target\n"); |
1598 | * @rport: remote port to be blocked. | ||
1599 | * | ||
1600 | * scsi lldd's with a FC transport call this routine to temporarily stop | ||
1601 | * all scsi traffic to a remote port. If the port is not a SCSI target, | ||
1602 | * no action is taken. If the port is a SCSI target, all attached devices | ||
1603 | * are placed into a SDEV_BLOCK state and a timer is started. The timer is | ||
1604 | * represents the maximum amount of time the port may be blocked. If the | ||
1605 | * timer expires, the port is considered non-existent and the attached | ||
1606 | * scsi devices will be removed. | ||
1607 | * | ||
1608 | * Called from interrupt or normal process context. | ||
1609 | * | ||
1610 | * Returns zero if successful or error if not | ||
1611 | * | ||
1612 | * Notes: | ||
1613 | * This routine assumes no locks are held on entry. | ||
1614 | * | ||
1615 | * The timeout and timer types are extracted from the fc transport | ||
1616 | * attributes from the caller's rport pointer. | ||
1617 | **/ | ||
1618 | int | ||
1619 | fc_remote_port_block(struct fc_rport *rport) | ||
1620 | { | ||
1621 | int timeout = rport->dev_loss_tmo; | ||
1622 | struct work_struct *work = &rport->dev_loss_work; | ||
1623 | 1733 | ||
1624 | if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) | 1734 | fc_rport_tgt_remove(rport); |
1625 | return -EINVAL; | ||
1626 | 1735 | ||
1627 | scsi_target_block(&rport->dev); | 1736 | return; |
1737 | } | ||
1628 | 1738 | ||
1629 | /* cap the length the devices can be blocked */ | 1739 | if (rport->port_state != FC_PORTSTATE_BLOCKED) { |
1630 | schedule_delayed_work(work, timeout * HZ); | 1740 | spin_unlock_irqrestore(shost->host_lock, flags); |
1741 | dev_printk(KERN_ERR, &rport->dev, | ||
1742 | "blocked FC remote port time out: leaving target alone\n"); | ||
1743 | return; | ||
1744 | } | ||
1631 | 1745 | ||
1632 | rport->port_state = FC_PORTSTATE_BLOCKED; | 1746 | if (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE) { |
1633 | return 0; | 1747 | spin_unlock_irqrestore(shost->host_lock, flags); |
1634 | } | 1748 | dev_printk(KERN_ERR, &rport->dev, |
1635 | EXPORT_SYMBOL(fc_remote_port_block); | 1749 | "blocked FC remote port time out: removing target\n"); |
1750 | fc_rport_terminate(rport); | ||
1751 | return; | ||
1752 | } | ||
1636 | 1753 | ||
1637 | /** | 1754 | dev_printk(KERN_ERR, &rport->dev, |
1638 | * fc_remote_port_unblock - restart any blocked scsi traffic to a remote port. | 1755 | "blocked FC remote port time out: removing target and " |
1639 | * @rport: remote port to be unblocked. | 1756 | "saving binding\n"); |
1640 | * | 1757 | |
1641 | * scsi lld's with a FC transport call this routine to restart IO to all | 1758 | list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); |
1642 | * devices associated with the caller's scsi target following a fc_target_block | ||
1643 | * request. Called from interrupt or normal process context. | ||
1644 | * | ||
1645 | * Notes: | ||
1646 | * This routine assumes no locks are held on entry. | ||
1647 | **/ | ||
1648 | void | ||
1649 | fc_remote_port_unblock(struct fc_rport *rport) | ||
1650 | { | ||
1651 | struct work_struct *work = &rport->dev_loss_work; | ||
1652 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
1653 | 1759 | ||
1654 | /* | 1760 | /* |
1655 | * Stop the target timer first. Take no action on the del_timer | 1761 | * Note: We do not remove or clear the hostdata area. This allows |
1656 | * failure as the state machine state change will validate the | 1762 | * host-specific target data to persist along with the |
1657 | * transaction. | 1763 | * scsi_target_id. It's up to the host to manage it's hostdata area. |
1658 | */ | 1764 | */ |
1659 | if (!cancel_delayed_work(work)) | ||
1660 | flush_scheduled_work(); | ||
1661 | 1765 | ||
1662 | if (rport->port_state == FC_PORTSTATE_OFFLINE) | 1766 | /* |
1663 | /* | 1767 | * Reinitialize port attributes that may change if the port comes back. |
1664 | * initiate a scan of the target as the target has | 1768 | */ |
1665 | * been torn down. | 1769 | rport->maxframe_size = -1; |
1666 | */ | 1770 | rport->supported_classes = FC_COS_UNSPECIFIED; |
1667 | scsi_queue_work(shost, &rport->scan_work); | 1771 | rport->roles = FC_RPORT_ROLE_UNKNOWN; |
1668 | else | 1772 | rport->port_state = FC_PORTSTATE_NOTPRESENT; |
1669 | scsi_target_unblock(&rport->dev); | ||
1670 | 1773 | ||
1671 | rport->port_state = FC_PORTSTATE_ONLINE; | 1774 | /* remove the identifiers that aren't used in the consisting binding */ |
1775 | switch (fc_host_tgtid_bind_type(shost)) { | ||
1776 | case FC_TGTID_BIND_BY_WWPN: | ||
1777 | rport->node_name = -1; | ||
1778 | rport->port_id = -1; | ||
1779 | break; | ||
1780 | case FC_TGTID_BIND_BY_WWNN: | ||
1781 | rport->port_name = -1; | ||
1782 | rport->port_id = -1; | ||
1783 | break; | ||
1784 | case FC_TGTID_BIND_BY_ID: | ||
1785 | rport->node_name = -1; | ||
1786 | rport->port_name = -1; | ||
1787 | break; | ||
1788 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | ||
1789 | break; | ||
1790 | } | ||
1791 | |||
1792 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1793 | |||
1794 | /* | ||
1795 | * As this only occurs if the remote port (scsi target) | ||
1796 | * went away and didn't come back - we'll remove | ||
1797 | * all attached scsi devices. | ||
1798 | */ | ||
1799 | fc_rport_tgt_remove(rport); | ||
1672 | } | 1800 | } |
1673 | EXPORT_SYMBOL(fc_remote_port_unblock); | ||
1674 | 1801 | ||
1675 | /** | 1802 | /** |
1676 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. | 1803 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. |
1804 | * | ||
1805 | * Will unblock the target (in case it went away and has now come back), | ||
1806 | * then invoke a scan. | ||
1807 | * | ||
1677 | * @data: remote port to be scanned. | 1808 | * @data: remote port to be scanned. |
1678 | **/ | 1809 | **/ |
1679 | static void | 1810 | static void |
@@ -1681,6 +1812,7 @@ fc_scsi_scan_rport(void *data) | |||
1681 | { | 1812 | { |
1682 | struct fc_rport *rport = (struct fc_rport *)data; | 1813 | struct fc_rport *rport = (struct fc_rport *)data; |
1683 | 1814 | ||
1815 | scsi_target_unblock(&rport->dev); | ||
1684 | scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, | 1816 | scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, |
1685 | SCAN_WILD_CARD, 1); | 1817 | SCAN_WILD_CARD, 1); |
1686 | } | 1818 | } |