diff options
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 28 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 19 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_scsi.c | 83 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_def.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_init.c | 26 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 21 | ||||
| -rw-r--r-- | drivers/scsi/qla2xxx/qla_rscn.c | 3 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 446 | ||||
| -rw-r--r-- | include/scsi/scsi_transport_fc.h | 31 |
9 files changed, 384 insertions, 276 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 56052f4510c3..6c846ad373bc 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c | |||
| @@ -1028,6 +1028,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba, | |||
| 1028 | if (ndlp->nlp_type & NLP_FCP_INITIATOR) | 1028 | if (ndlp->nlp_type & NLP_FCP_INITIATOR) |
| 1029 | rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; | 1029 | rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; |
| 1030 | 1030 | ||
| 1031 | scsi_block_requests(phba->host); | ||
| 1031 | ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); | 1032 | ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); |
| 1032 | if (!rport) { | 1033 | if (!rport) { |
| 1033 | dev_printk(KERN_WARNING, &phba->pcidev->dev, | 1034 | dev_printk(KERN_WARNING, &phba->pcidev->dev, |
| @@ -1044,6 +1045,23 @@ lpfc_register_remote_port(struct lpfc_hba * phba, | |||
| 1044 | } | 1045 | } |
| 1045 | rdata = rport->dd_data; | 1046 | rdata = rport->dd_data; |
| 1046 | rdata->pnode = ndlp; | 1047 | rdata->pnode = ndlp; |
| 1048 | scsi_unblock_requests(phba->host); | ||
| 1049 | |||
| 1050 | return; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | static void | ||
| 1054 | lpfc_unregister_remote_port(struct lpfc_hba * phba, | ||
| 1055 | struct lpfc_nodelist * ndlp) | ||
| 1056 | { | ||
| 1057 | struct fc_rport *rport = ndlp->rport; | ||
| 1058 | struct lpfc_rport_data *rdata = rport->dd_data; | ||
| 1059 | |||
| 1060 | ndlp->rport = NULL; | ||
| 1061 | rdata->pnode = NULL; | ||
| 1062 | scsi_block_requests(phba->host); | ||
| 1063 | fc_remote_port_delete(rport); | ||
| 1064 | scsi_unblock_requests(phba->host); | ||
| 1047 | 1065 | ||
| 1048 | return; | 1066 | return; |
| 1049 | } | 1067 | } |
| @@ -1260,7 +1278,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) | |||
| 1260 | * may have removed the remote port. | 1278 | * may have removed the remote port. |
| 1261 | */ | 1279 | */ |
| 1262 | if ((rport_del != none) && nlp->rport) | 1280 | if ((rport_del != none) && nlp->rport) |
| 1263 | fc_remote_port_block(nlp->rport); | 1281 | lpfc_unregister_remote_port(phba, nlp); |
| 1264 | 1282 | ||
| 1265 | if (rport_add != none) { | 1283 | if (rport_add != none) { |
| 1266 | /* | 1284 | /* |
| @@ -1270,8 +1288,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) | |||
| 1270 | */ | 1288 | */ |
| 1271 | if (!nlp->rport) | 1289 | if (!nlp->rport) |
| 1272 | lpfc_register_remote_port(phba, nlp); | 1290 | lpfc_register_remote_port(phba, nlp); |
| 1273 | else | ||
| 1274 | fc_remote_port_unblock(nlp->rport); | ||
| 1275 | 1291 | ||
| 1276 | /* | 1292 | /* |
| 1277 | * if we added to Mapped list, but the remote port | 1293 | * if we added to Mapped list, but the remote port |
| @@ -1490,7 +1506,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
| 1490 | LPFC_MBOXQ_t *mb; | 1506 | LPFC_MBOXQ_t *mb; |
| 1491 | LPFC_MBOXQ_t *nextmb; | 1507 | LPFC_MBOXQ_t *nextmb; |
| 1492 | struct lpfc_dmabuf *mp; | 1508 | struct lpfc_dmabuf *mp; |
| 1493 | struct fc_rport *rport; | ||
| 1494 | 1509 | ||
| 1495 | /* Cleanup node for NPort <nlp_DID> */ | 1510 | /* Cleanup node for NPort <nlp_DID> */ |
| 1496 | lpfc_printf_log(phba, KERN_INFO, LOG_NODE, | 1511 | lpfc_printf_log(phba, KERN_INFO, LOG_NODE, |
| @@ -1507,10 +1522,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) | |||
| 1507 | * and flush cache's w/o generating flush errors. | 1522 | * and flush cache's w/o generating flush errors. |
| 1508 | */ | 1523 | */ |
| 1509 | if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { | 1524 | if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { |
| 1510 | rport = ndlp->rport; | 1525 | lpfc_unregister_remote_port(phba, ndlp); |
| 1511 | ndlp->rport = NULL; | ||
| 1512 | fc_remote_port_unblock(rport); | ||
| 1513 | fc_remote_port_delete(rport); | ||
| 1514 | ndlp->nlp_sid = NLP_NO_SID; | 1526 | ndlp->nlp_sid = NLP_NO_SID; |
| 1515 | } | 1527 | } |
| 1516 | 1528 | ||
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 0856ff7d3b33..25d55f40424f 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c | |||
| @@ -537,12 +537,6 @@ lpfc_handle_eratt(struct lpfc_hba * phba) | |||
| 537 | 537 | ||
| 538 | lpfc_offline(phba); | 538 | lpfc_offline(phba); |
| 539 | 539 | ||
| 540 | /* | ||
| 541 | * Restart all traffic to this host. Since the fc_transport | ||
| 542 | * block functions (future) were not called in lpfc_offline, | ||
| 543 | * don't call them here. | ||
| 544 | */ | ||
| 545 | scsi_unblock_requests(phba->host); | ||
| 546 | } | 540 | } |
| 547 | } | 541 | } |
| 548 | 542 | ||
| @@ -1226,12 +1220,6 @@ lpfc_online(struct lpfc_hba * phba) | |||
| 1226 | phba->fc_flag &= ~FC_OFFLINE_MODE; | 1220 | phba->fc_flag &= ~FC_OFFLINE_MODE; |
| 1227 | spin_unlock_irq(phba->host->host_lock); | 1221 | spin_unlock_irq(phba->host->host_lock); |
| 1228 | 1222 | ||
| 1229 | /* | ||
| 1230 | * Restart all traffic to this host. Since the fc_transport block | ||
| 1231 | * functions (future) were not called in lpfc_offline, don't call them | ||
| 1232 | * here. | ||
| 1233 | */ | ||
| 1234 | scsi_unblock_requests(phba->host); | ||
| 1235 | return 0; | 1223 | return 0; |
| 1236 | } | 1224 | } |
| 1237 | 1225 | ||
| @@ -1249,13 +1237,6 @@ lpfc_offline(struct lpfc_hba * phba) | |||
| 1249 | if (phba->fc_flag & FC_OFFLINE_MODE) | 1237 | if (phba->fc_flag & FC_OFFLINE_MODE) |
| 1250 | return 0; | 1238 | return 0; |
| 1251 | 1239 | ||
| 1252 | /* | ||
| 1253 | * Don't call the fc_transport block api (future). The device is | ||
| 1254 | * going offline and causing a timer to fire in the midlayer is | ||
| 1255 | * unproductive. Just block all new requests until the driver | ||
| 1256 | * comes back online. | ||
| 1257 | */ | ||
| 1258 | scsi_block_requests(phba->host); | ||
| 1259 | psli = &phba->sli; | 1240 | psli = &phba->sli; |
| 1260 | pring = &psli->ring[psli->fcp_ring]; | 1241 | pring = &psli->ring[psli->fcp_ring]; |
| 1261 | 1242 | ||
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index b5ad1871d34b..c55ab1a630e5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c | |||
| @@ -403,14 +403,9 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, | |||
| 403 | break; | 403 | break; |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | if (pnode) { | 406 | if ((pnode == NULL ) |
| 407 | if (pnode->nlp_state != NLP_STE_MAPPED_NODE) | 407 | || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) |
| 408 | cmd->result = ScsiResult(DID_BUS_BUSY, | 408 | cmd->result = ScsiResult(DID_BUS_BUSY, SAM_STAT_BUSY); |
| 409 | SAM_STAT_BUSY); | ||
| 410 | } | ||
| 411 | else { | ||
| 412 | cmd->result = ScsiResult(DID_NO_CONNECT, 0); | ||
| 413 | } | ||
| 414 | } else { | 409 | } else { |
| 415 | cmd->result = ScsiResult(DID_OK, 0); | 410 | cmd->result = ScsiResult(DID_OK, 0); |
| 416 | } | 411 | } |
| @@ -539,7 +534,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, | |||
| 539 | struct lpfc_rport_data *rdata = scsi_dev->hostdata; | 534 | struct lpfc_rport_data *rdata = scsi_dev->hostdata; |
| 540 | struct lpfc_nodelist *ndlp = rdata->pnode; | 535 | struct lpfc_nodelist *ndlp = rdata->pnode; |
| 541 | 536 | ||
| 542 | if ((ndlp == 0) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { | 537 | if ((ndlp == NULL) || (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { |
| 543 | return 0; | 538 | return 0; |
| 544 | } | 539 | } |
| 545 | 540 | ||
| @@ -727,39 +722,23 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) | |||
| 727 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; | 722 | struct lpfc_rport_data *rdata = cmnd->device->hostdata; |
| 728 | struct lpfc_nodelist *ndlp = rdata->pnode; | 723 | struct lpfc_nodelist *ndlp = rdata->pnode; |
| 729 | struct lpfc_scsi_buf *lpfc_cmd = NULL; | 724 | struct lpfc_scsi_buf *lpfc_cmd = NULL; |
| 725 | struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); | ||
| 730 | struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; | 726 | struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; |
| 731 | int err = 0; | 727 | int err; |
| 732 | 728 | ||
| 733 | /* | 729 | err = fc_remote_port_chkready(rport); |
| 734 | * The target pointer is guaranteed not to be NULL because the driver | 730 | if (err) { |
| 735 | * only clears the device->hostdata field in lpfc_slave_destroy. This | 731 | cmnd->result = err; |
| 736 | * approach guarantees no further IO calls on this target. | ||
| 737 | */ | ||
| 738 | if (!ndlp) { | ||
| 739 | cmnd->result = ScsiResult(DID_NO_CONNECT, 0); | ||
| 740 | goto out_fail_command; | 732 | goto out_fail_command; |
| 741 | } | 733 | } |
| 742 | 734 | ||
| 743 | /* | 735 | /* |
| 744 | * A Fibre Channel target is present and functioning only when the node | 736 | * Catch race where our node has transitioned, but the |
| 745 | * state is MAPPED. Any other state is a failure. | 737 | * transport is still transitioning. |
| 746 | */ | 738 | */ |
| 747 | if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { | 739 | if (!ndlp) { |
| 748 | if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || | 740 | cmnd->result = ScsiResult(DID_BUS_BUSY, 0); |
| 749 | (ndlp->nlp_state == NLP_STE_UNUSED_NODE)) { | 741 | goto out_fail_command; |
| 750 | cmnd->result = ScsiResult(DID_NO_CONNECT, 0); | ||
| 751 | goto out_fail_command; | ||
| 752 | } | ||
| 753 | else if (ndlp->nlp_state == NLP_STE_NPR_NODE) { | ||
| 754 | cmnd->result = ScsiResult(DID_BUS_BUSY, 0); | ||
| 755 | goto out_fail_command; | ||
| 756 | } | ||
| 757 | /* | ||
| 758 | * The device is most likely recovered and the driver | ||
| 759 | * needs a bit more time to finish. Ask the midlayer | ||
| 760 | * to retry. | ||
| 761 | */ | ||
| 762 | goto out_host_busy; | ||
| 763 | } | 742 | } |
| 764 | 743 | ||
| 765 | list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); | 744 | list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); |
| @@ -1163,44 +1142,16 @@ static int | |||
| 1163 | lpfc_slave_alloc(struct scsi_device *sdev) | 1142 | lpfc_slave_alloc(struct scsi_device *sdev) |
| 1164 | { | 1143 | { |
| 1165 | struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0]; | 1144 | struct lpfc_hba *phba = (struct lpfc_hba *)sdev->host->hostdata[0]; |
| 1166 | struct lpfc_nodelist *ndlp = NULL; | ||
| 1167 | int match = 0; | ||
| 1168 | struct lpfc_scsi_buf *scsi_buf = NULL; | 1145 | struct lpfc_scsi_buf *scsi_buf = NULL; |
| 1146 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
| 1169 | uint32_t total = 0, i; | 1147 | uint32_t total = 0, i; |
| 1170 | uint32_t num_to_alloc = 0; | 1148 | uint32_t num_to_alloc = 0; |
| 1171 | unsigned long flags; | 1149 | unsigned long flags; |
| 1172 | struct list_head *listp; | ||
| 1173 | struct list_head *node_list[6]; | ||
| 1174 | |||
| 1175 | /* | ||
| 1176 | * Store the target pointer in the scsi_device hostdata pointer provided | ||
| 1177 | * the driver has already discovered the target id. | ||
| 1178 | */ | ||
| 1179 | |||
| 1180 | /* Search the nlp lists other than unmap_list for this target ID */ | ||
| 1181 | node_list[0] = &phba->fc_npr_list; | ||
| 1182 | node_list[1] = &phba->fc_nlpmap_list; | ||
| 1183 | node_list[2] = &phba->fc_prli_list; | ||
| 1184 | node_list[3] = &phba->fc_reglogin_list; | ||
| 1185 | node_list[4] = &phba->fc_adisc_list; | ||
| 1186 | node_list[5] = &phba->fc_plogi_list; | ||
| 1187 | |||
| 1188 | for (i = 0; i < 6 && !match; i++) { | ||
| 1189 | listp = node_list[i]; | ||
| 1190 | if (list_empty(listp)) | ||
| 1191 | continue; | ||
| 1192 | list_for_each_entry(ndlp, listp, nlp_listp) { | ||
| 1193 | if ((sdev->id == ndlp->nlp_sid) && ndlp->rport) { | ||
| 1194 | match = 1; | ||
| 1195 | break; | ||
| 1196 | } | ||
| 1197 | } | ||
| 1198 | } | ||
| 1199 | 1150 | ||
| 1200 | if (!match) | 1151 | if (!rport || fc_remote_port_chkready(rport)) |
| 1201 | return -ENXIO; | 1152 | return -ENXIO; |
| 1202 | 1153 | ||
| 1203 | sdev->hostdata = ndlp->rport->dd_data; | 1154 | sdev->hostdata = rport->dd_data; |
| 1204 | 1155 | ||
| 1205 | /* | 1156 | /* |
| 1206 | * Populate the cmds_per_lun count scsi_bufs into this host's globally | 1157 | * Populate the cmds_per_lun count scsi_bufs into this host's globally |
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index fc3234c3625b..7096945ea234 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
| 22 | #include <linux/completion.h> | 22 | #include <linux/completion.h> |
| 23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
| 24 | #include <linux/workqueue.h> | ||
| 24 | #include <asm/semaphore.h> | 25 | #include <asm/semaphore.h> |
| 25 | 26 | ||
| 26 | #include <scsi/scsi.h> | 27 | #include <scsi/scsi.h> |
| @@ -1665,6 +1666,8 @@ typedef struct fc_port { | |||
| 1665 | 1666 | ||
| 1666 | struct fc_rport *rport; | 1667 | struct fc_rport *rport; |
| 1667 | u32 supported_classes; | 1668 | u32 supported_classes; |
| 1669 | struct work_struct rport_add_work; | ||
| 1670 | struct work_struct rport_del_work; | ||
| 1668 | } fc_port_t; | 1671 | } fc_port_t; |
| 1669 | 1672 | ||
| 1670 | /* | 1673 | /* |
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ce7e712ebe8d..290a6b92616c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c | |||
| @@ -1668,6 +1668,24 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) | |||
| 1668 | return (rval); | 1668 | return (rval); |
| 1669 | } | 1669 | } |
| 1670 | 1670 | ||
| 1671 | static void | ||
| 1672 | qla2x00_rport_add(void *data) | ||
| 1673 | { | ||
| 1674 | fc_port_t *fcport = data; | ||
| 1675 | |||
| 1676 | qla2x00_reg_remote_port(fcport->ha, fcport); | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | static void | ||
| 1680 | qla2x00_rport_del(void *data) | ||
| 1681 | { | ||
| 1682 | fc_port_t *fcport = data; | ||
| 1683 | |||
| 1684 | if (fcport->rport) | ||
| 1685 | fc_remote_port_delete(fcport->rport); | ||
| 1686 | fcport->rport = NULL; | ||
| 1687 | } | ||
| 1688 | |||
| 1671 | /** | 1689 | /** |
| 1672 | * qla2x00_alloc_fcport() - Allocate a generic fcport. | 1690 | * qla2x00_alloc_fcport() - Allocate a generic fcport. |
| 1673 | * @ha: HA context | 1691 | * @ha: HA context |
| @@ -1693,6 +1711,8 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) | |||
| 1693 | atomic_set(&fcport->state, FCS_UNCONFIGURED); | 1711 | atomic_set(&fcport->state, FCS_UNCONFIGURED); |
| 1694 | fcport->flags = FCF_RLC_SUPPORT; | 1712 | fcport->flags = FCF_RLC_SUPPORT; |
| 1695 | fcport->supported_classes = FC_COS_UNSPECIFIED; | 1713 | fcport->supported_classes = FC_COS_UNSPECIFIED; |
| 1714 | INIT_WORK(&fcport->rport_add_work, qla2x00_rport_add, fcport); | ||
| 1715 | INIT_WORK(&fcport->rport_del_work, qla2x00_rport_del, fcport); | ||
| 1696 | 1716 | ||
| 1697 | return (fcport); | 1717 | return (fcport); |
| 1698 | } | 1718 | } |
| @@ -2056,8 +2076,8 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) | |||
| 2056 | struct fc_rport *rport; | 2076 | struct fc_rport *rport; |
| 2057 | 2077 | ||
| 2058 | if (fcport->rport) { | 2078 | if (fcport->rport) { |
| 2059 | fc_remote_port_unblock(fcport->rport); | 2079 | fc_remote_port_delete(fcport->rport); |
| 2060 | return; | 2080 | fcport->rport = NULL; |
| 2061 | } | 2081 | } |
| 2062 | 2082 | ||
| 2063 | rport_ids.node_name = wwn_to_u64(fcport->node_name); | 2083 | rport_ids.node_name = wwn_to_u64(fcport->node_name); |
| @@ -2071,7 +2091,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) | |||
| 2071 | "Unable to allocate fc remote port!\n"); | 2091 | "Unable to allocate fc remote port!\n"); |
| 2072 | return; | 2092 | return; |
| 2073 | } | 2093 | } |
| 2074 | rport->dd_data = fcport; | 2094 | *((fc_port_t **)rport->dd_data) = fcport; |
| 2075 | rport->supported_classes = fcport->supported_classes; | 2095 | rport->supported_classes = fcport->supported_classes; |
| 2076 | 2096 | ||
| 2077 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; | 2097 | rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index b899282a856e..c58c9d97b041 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
| @@ -348,11 +348,13 @@ qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
| 348 | { | 348 | { |
| 349 | scsi_qla_host_t *ha = to_qla_host(cmd->device->host); | 349 | scsi_qla_host_t *ha = to_qla_host(cmd->device->host); |
| 350 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; | 350 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; |
| 351 | struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); | ||
| 351 | srb_t *sp; | 352 | srb_t *sp; |
| 352 | int rval; | 353 | int rval; |
| 353 | 354 | ||
| 354 | if (!fcport) { | 355 | rval = fc_remote_port_chkready(rport); |
| 355 | cmd->result = DID_NO_CONNECT << 16; | 356 | if (rval) { |
| 357 | cmd->result = rval; | ||
| 356 | goto qc_fail_command; | 358 | goto qc_fail_command; |
| 357 | } | 359 | } |
| 358 | 360 | ||
| @@ -401,11 +403,13 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) | |||
| 401 | { | 403 | { |
| 402 | scsi_qla_host_t *ha = to_qla_host(cmd->device->host); | 404 | scsi_qla_host_t *ha = to_qla_host(cmd->device->host); |
| 403 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; | 405 | fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; |
| 406 | struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); | ||
| 404 | srb_t *sp; | 407 | srb_t *sp; |
| 405 | int rval; | 408 | int rval; |
| 406 | 409 | ||
| 407 | if (!fcport) { | 410 | rval = fc_remote_port_chkready(rport); |
| 408 | cmd->result = DID_NO_CONNECT << 16; | 411 | if (rval) { |
| 412 | cmd->result = rval; | ||
| 409 | goto qc24_fail_command; | 413 | goto qc24_fail_command; |
| 410 | } | 414 | } |
| 411 | 415 | ||
| @@ -1041,10 +1045,10 @@ qla2xxx_slave_alloc(struct scsi_device *sdev) | |||
| 1041 | { | 1045 | { |
| 1042 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | 1046 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); |
| 1043 | 1047 | ||
| 1044 | if (!rport) | 1048 | if (!rport || fc_remote_port_chkready(rport)) |
| 1045 | return -ENXIO; | 1049 | return -ENXIO; |
| 1046 | 1050 | ||
| 1047 | sdev->hostdata = rport->dd_data; | 1051 | sdev->hostdata = *(fc_port_t **)rport->dd_data; |
| 1048 | 1052 | ||
| 1049 | return 0; | 1053 | return 0; |
| 1050 | } | 1054 | } |
| @@ -1636,7 +1640,8 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport, | |||
| 1636 | int do_login) | 1640 | int do_login) |
| 1637 | { | 1641 | { |
| 1638 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) | 1642 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) |
| 1639 | fc_remote_port_block(fcport->rport); | 1643 | schedule_work(&fcport->rport_del_work); |
| 1644 | |||
| 1640 | /* | 1645 | /* |
| 1641 | * We may need to retry the login, so don't change the state of the | 1646 | * We may need to retry the login, so don't change the state of the |
| 1642 | * port but do the retries. | 1647 | * port but do the retries. |
| @@ -1697,7 +1702,7 @@ qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) | |||
| 1697 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) | 1702 | if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) |
| 1698 | continue; | 1703 | continue; |
| 1699 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) | 1704 | if (atomic_read(&fcport->state) == FCS_ONLINE && fcport->rport) |
| 1700 | fc_remote_port_block(fcport->rport); | 1705 | schedule_work(&fcport->rport_del_work); |
| 1701 | atomic_set(&fcport->state, FCS_DEVICE_LOST); | 1706 | atomic_set(&fcport->state, FCS_DEVICE_LOST); |
| 1702 | } | 1707 | } |
| 1703 | } | 1708 | } |
diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c index 3e53f62d640d..2c3342108dd8 100644 --- a/drivers/scsi/qla2xxx/qla_rscn.c +++ b/drivers/scsi/qla2xxx/qla_rscn.c | |||
| @@ -320,8 +320,7 @@ qla2x00_update_login_fcport(scsi_qla_host_t *ha, struct mbx_entry *mbxstat, | |||
| 320 | fcport->flags &= ~FCF_FAILOVER_NEEDED; | 320 | fcport->flags &= ~FCF_FAILOVER_NEEDED; |
| 321 | fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; | 321 | fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; |
| 322 | atomic_set(&fcport->state, FCS_ONLINE); | 322 | atomic_set(&fcport->state, FCS_ONLINE); |
| 323 | if (fcport->rport) | 323 | schedule_work(&fcport->rport_add_work); |
| 324 | fc_remote_port_unblock(fcport->rport); | ||
| 325 | } | 324 | } |
| 326 | 325 | ||
| 327 | 326 | ||
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 27702097b7fc..ca098fc2a607 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
| @@ -210,7 +210,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) | |||
| 210 | #define FC_MGMTSRVR_PORTID 0x00000a | 210 | #define FC_MGMTSRVR_PORTID 0x00000a |
| 211 | 211 | ||
| 212 | 212 | ||
| 213 | static void fc_timeout_blocked_rport(void *data); | 213 | static void fc_timeout_deleted_rport(void *data); |
| 214 | static void fc_scsi_scan_rport(void *data); | 214 | static void fc_scsi_scan_rport(void *data); |
| 215 | static void fc_rport_terminate(struct fc_rport *rport); | 215 | static void fc_rport_terminate(struct fc_rport *rport); |
| 216 | 216 | ||
| @@ -384,7 +384,9 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ | |||
| 384 | struct fc_rport *rport = transport_class_to_rport(cdev); \ | 384 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
| 385 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 385 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
| 386 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 386 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
| 387 | if (i->f->get_rport_##field) \ | 387 | if ((i->f->get_rport_##field) && \ |
| 388 | !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | ||
| 389 | (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ | ||
| 388 | i->f->get_rport_##field(rport); \ | 390 | i->f->get_rport_##field(rport); \ |
| 389 | return snprintf(buf, sz, format_string, cast rport->field); \ | 391 | return snprintf(buf, sz, format_string, cast rport->field); \ |
| 390 | } | 392 | } |
| @@ -398,6 +400,9 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ | |||
| 398 | struct fc_rport *rport = transport_class_to_rport(cdev); \ | 400 | struct fc_rport *rport = transport_class_to_rport(cdev); \ |
| 399 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 401 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
| 400 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 402 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
| 403 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | ||
| 404 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ | ||
| 405 | return -EBUSY; \ | ||
| 401 | val = simple_strtoul(buf, NULL, 0); \ | 406 | val = simple_strtoul(buf, NULL, 0); \ |
| 402 | i->f->set_rport_##field(rport, val); \ | 407 | i->f->set_rport_##field(rport, val); \ |
| 403 | return count; \ | 408 | return count; \ |
| @@ -500,7 +505,29 @@ static FC_CLASS_DEVICE_ATTR(rport, supported_classes, S_IRUGO, | |||
| 500 | 505 | ||
| 501 | /* Dynamic Remote Port Attributes */ | 506 | /* Dynamic Remote Port Attributes */ |
| 502 | 507 | ||
| 503 | fc_rport_rw_attr(dev_loss_tmo, "%d\n", 20); | 508 | /* |
| 509 | * dev_loss_tmo attribute | ||
| 510 | */ | ||
| 511 | fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) | ||
| 512 | static ssize_t | ||
| 513 | store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, | ||
| 514 | size_t count) | ||
| 515 | { | ||
| 516 | int val; | ||
| 517 | struct fc_rport *rport = transport_class_to_rport(cdev); | ||
| 518 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
| 519 | struct fc_internal *i = to_fc_internal(shost->transportt); | ||
| 520 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | ||
| 521 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | ||
| 522 | return -EBUSY; | ||
| 523 | val = simple_strtoul(buf, NULL, 0); | ||
| 524 | if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) | ||
| 525 | return -EINVAL; | ||
| 526 | i->f->set_rport_dev_loss_tmo(rport, val); | ||
| 527 | return count; | ||
| 528 | } | ||
| 529 | static FC_CLASS_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, | ||
| 530 | show_fc_rport_dev_loss_tmo, store_fc_rport_dev_loss_tmo); | ||
| 504 | 531 | ||
| 505 | 532 | ||
| 506 | /* Private Remote Port Attributes */ | 533 | /* Private Remote Port Attributes */ |
| @@ -1214,6 +1241,25 @@ fc_remove_host(struct Scsi_Host *shost) | |||
| 1214 | } | 1241 | } |
| 1215 | EXPORT_SYMBOL(fc_remove_host); | 1242 | EXPORT_SYMBOL(fc_remove_host); |
| 1216 | 1243 | ||
| 1244 | /* | ||
| 1245 | * fc_rport_tgt_remove - Removes the scsi target on the remote port | ||
| 1246 | * @rport: The remote port to be operated on | ||
| 1247 | */ | ||
| 1248 | static void | ||
| 1249 | fc_rport_tgt_remove(struct fc_rport *rport) | ||
| 1250 | { | ||
| 1251 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
| 1252 | |||
| 1253 | scsi_target_unblock(&rport->dev); | ||
| 1254 | |||
| 1255 | /* Stop anything on the workq */ | ||
| 1256 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
| 1257 | flush_scheduled_work(); | ||
| 1258 | scsi_flush_work(shost); | ||
| 1259 | |||
| 1260 | scsi_remove_target(&rport->dev); | ||
| 1261 | } | ||
| 1262 | |||
| 1217 | /** | 1263 | /** |
| 1218 | * fc_rport_create - allocates and creates a remote FC port. | 1264 | * fc_rport_create - allocates and creates a remote FC port. |
| 1219 | * @shost: scsi host the remote port is connected to. | 1265 | * @shost: scsi host the remote port is connected to. |
| @@ -1260,7 +1306,7 @@ fc_rport_create(struct Scsi_Host *shost, int channel, | |||
| 1260 | rport->dd_data = &rport[1]; | 1306 | rport->dd_data = &rport[1]; |
| 1261 | rport->channel = channel; | 1307 | rport->channel = channel; |
| 1262 | 1308 | ||
| 1263 | INIT_WORK(&rport->dev_loss_work, fc_timeout_blocked_rport, rport); | 1309 | INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport); |
| 1264 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); | 1310 | INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport); |
| 1265 | 1311 | ||
| 1266 | spin_lock_irqsave(shost->host_lock, flags); | 1312 | spin_lock_irqsave(shost->host_lock, flags); |
| @@ -1352,17 +1398,93 @@ struct fc_rport * | |||
| 1352 | fc_remote_port_add(struct Scsi_Host *shost, int channel, | 1398 | fc_remote_port_add(struct Scsi_Host *shost, int channel, |
| 1353 | struct fc_rport_identifiers *ids) | 1399 | struct fc_rport_identifiers *ids) |
| 1354 | { | 1400 | { |
| 1401 | struct fc_internal *fci = to_fc_internal(shost->transportt); | ||
| 1355 | struct fc_rport *rport; | 1402 | struct fc_rport *rport; |
| 1356 | unsigned long flags; | 1403 | unsigned long flags; |
| 1357 | int match = 0; | 1404 | int match = 0; |
| 1358 | 1405 | ||
| 1406 | /* | ||
| 1407 | * Search the list of "active" rports, for an rport that has been | ||
| 1408 | * deleted, but we've held off the real delete while the target | ||
| 1409 | * is in a "blocked" state. | ||
| 1410 | */ | ||
| 1411 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 1412 | |||
| 1413 | list_for_each_entry(rport, &fc_host_rports(shost), peers) { | ||
| 1414 | |||
| 1415 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) && | ||
| 1416 | (rport->channel == channel)) { | ||
| 1417 | |||
| 1418 | switch (fc_host_tgtid_bind_type(shost)) { | ||
| 1419 | case FC_TGTID_BIND_BY_WWPN: | ||
| 1420 | case FC_TGTID_BIND_NONE: | ||
| 1421 | if (rport->port_name == ids->port_name) | ||
| 1422 | match = 1; | ||
| 1423 | break; | ||
| 1424 | case FC_TGTID_BIND_BY_WWNN: | ||
| 1425 | if (rport->node_name == ids->node_name) | ||
| 1426 | match = 1; | ||
| 1427 | break; | ||
| 1428 | case FC_TGTID_BIND_BY_ID: | ||
| 1429 | if (rport->port_id == ids->port_id) | ||
| 1430 | match = 1; | ||
| 1431 | break; | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | if (match) { | ||
| 1435 | struct work_struct *work = | ||
| 1436 | &rport->dev_loss_work; | ||
| 1437 | |||
| 1438 | memcpy(&rport->node_name, &ids->node_name, | ||
| 1439 | sizeof(rport->node_name)); | ||
| 1440 | memcpy(&rport->port_name, &ids->port_name, | ||
| 1441 | sizeof(rport->port_name)); | ||
| 1442 | rport->port_id = ids->port_id; | ||
| 1443 | |||
| 1444 | rport->port_state = FC_PORTSTATE_ONLINE; | ||
| 1445 | rport->roles = ids->roles; | ||
| 1446 | |||
| 1447 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1448 | |||
| 1449 | if (fci->f->dd_fcrport_size) | ||
| 1450 | memset(rport->dd_data, 0, | ||
| 1451 | fci->f->dd_fcrport_size); | ||
| 1452 | |||
| 1453 | /* | ||
| 1454 | * If we were blocked, we were a target. | ||
| 1455 | * If no longer a target, we leave the timer | ||
| 1456 | * running in case the port changes roles | ||
| 1457 | * prior to the timer expiring. If the timer | ||
| 1458 | * fires, the target will be torn down. | ||
| 1459 | */ | ||
| 1460 | if (!(ids->roles & FC_RPORT_ROLE_FCP_TARGET)) | ||
| 1461 | return rport; | ||
| 1462 | |||
| 1463 | /* restart the target */ | ||
| 1464 | |||
| 1465 | /* | ||
| 1466 | * Stop the target timer first. Take no action | ||
| 1467 | * on the del_timer failure as the state | ||
| 1468 | * machine state change will validate the | ||
| 1469 | * transaction. | ||
| 1470 | */ | ||
| 1471 | if (!cancel_delayed_work(work)) | ||
| 1472 | flush_scheduled_work(); | ||
| 1473 | |||
| 1474 | /* initiate a scan of the target */ | ||
| 1475 | scsi_queue_work(shost, &rport->scan_work); | ||
| 1476 | |||
| 1477 | return rport; | ||
| 1478 | } | ||
| 1479 | } | ||
| 1480 | } | ||
| 1481 | |||
| 1482 | /* Search the bindings array */ | ||
| 1359 | if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) && | 1483 | if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) && |
| 1360 | (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) { | 1484 | (fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) { |
| 1361 | 1485 | ||
| 1362 | /* search for a matching consistent binding */ | 1486 | /* search for a matching consistent binding */ |
| 1363 | 1487 | ||
| 1364 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 1365 | |||
| 1366 | list_for_each_entry(rport, &fc_host_rport_bindings(shost), | 1488 | list_for_each_entry(rport, &fc_host_rport_bindings(shost), |
| 1367 | peers) { | 1489 | peers) { |
| 1368 | if (rport->channel != channel) | 1490 | if (rport->channel != channel) |
| @@ -1392,8 +1514,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
| 1392 | } | 1514 | } |
| 1393 | } | 1515 | } |
| 1394 | 1516 | ||
| 1395 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1396 | |||
| 1397 | if (match) { | 1517 | if (match) { |
| 1398 | memcpy(&rport->node_name, &ids->node_name, | 1518 | memcpy(&rport->node_name, &ids->node_name, |
| 1399 | sizeof(rport->node_name)); | 1519 | sizeof(rport->node_name)); |
| @@ -1403,6 +1523,12 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
| 1403 | rport->roles = ids->roles; | 1523 | rport->roles = ids->roles; |
| 1404 | rport->port_state = FC_PORTSTATE_ONLINE; | 1524 | rport->port_state = FC_PORTSTATE_ONLINE; |
| 1405 | 1525 | ||
| 1526 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1527 | |||
| 1528 | if (fci->f->dd_fcrport_size) | ||
| 1529 | memset(rport->dd_data, 0, | ||
| 1530 | fci->f->dd_fcrport_size); | ||
| 1531 | |||
| 1406 | if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) | 1532 | if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) |
| 1407 | /* initiate a scan of the target */ | 1533 | /* initiate a scan of the target */ |
| 1408 | scsi_queue_work(shost, &rport->scan_work); | 1534 | scsi_queue_work(shost, &rport->scan_work); |
| @@ -1411,6 +1537,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
| 1411 | } | 1537 | } |
| 1412 | } | 1538 | } |
| 1413 | 1539 | ||
| 1540 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1541 | |||
| 1414 | /* No consistent binding found - create new remote port entry */ | 1542 | /* No consistent binding found - create new remote port entry */ |
| 1415 | rport = fc_rport_create(shost, channel, ids); | 1543 | rport = fc_rport_create(shost, channel, ids); |
| 1416 | 1544 | ||
| @@ -1419,25 +1547,6 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, | |||
| 1419 | EXPORT_SYMBOL(fc_remote_port_add); | 1547 | EXPORT_SYMBOL(fc_remote_port_add); |
| 1420 | 1548 | ||
| 1421 | /* | 1549 | /* |
| 1422 | * fc_rport_tgt_remove - Removes the scsi target on the remote port | ||
| 1423 | * @rport: The remote port to be operated on | ||
| 1424 | */ | ||
| 1425 | static void | ||
| 1426 | fc_rport_tgt_remove(struct fc_rport *rport) | ||
| 1427 | { | ||
| 1428 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
| 1429 | |||
| 1430 | scsi_target_unblock(&rport->dev); | ||
| 1431 | |||
| 1432 | /* Stop anything on the workq */ | ||
| 1433 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
| 1434 | flush_scheduled_work(); | ||
| 1435 | scsi_flush_work(shost); | ||
| 1436 | |||
| 1437 | scsi_remove_target(&rport->dev); | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | /* | ||
| 1441 | * fc_rport_terminate - this routine tears down and deallocates a remote port. | 1550 | * fc_rport_terminate - this routine tears down and deallocates a remote port. |
| 1442 | * @rport: The remote port to be terminated | 1551 | * @rport: The remote port to be terminated |
| 1443 | * | 1552 | * |
| @@ -1470,24 +1579,44 @@ fc_rport_terminate(struct fc_rport *rport) | |||
| 1470 | * The LLDD calls this routine to notify the transport that a remote | 1579 | * The LLDD calls this routine to notify the transport that a remote |
| 1471 | * port is no longer part of the topology. Note: Although a port | 1580 | * port is no longer part of the topology. Note: Although a port |
| 1472 | * may no longer be part of the topology, it may persist in the remote | 1581 | * may no longer be part of the topology, it may persist in the remote |
| 1473 | * ports displayed by the fc_host. This is done so that target id | 1582 | * ports displayed by the fc_host. We do this under 2 conditions: |
| 1474 | * mappings (managed via the remote port structures), are always visible | 1583 | * - If the port was a scsi target, we delay its deletion by "blocking" it. |
| 1475 | * as long as the mapping is valid, regardless of port state, | 1584 | * This allows the port to temporarily disappear, then reappear without |
| 1585 | * disrupting the SCSI device tree attached to it. During the "blocked" | ||
| 1586 | * period the port will still exist. | ||
| 1587 | * - If the port was a scsi target and disappears for longer than we | ||
| 1588 | * expect, we'll delete the port and the tear down the SCSI device tree | ||
| 1589 | * attached to it. However, we want to semi-persist the target id assigned | ||
| 1590 | * to that port if it eventually does exist. The port structure will | ||
| 1591 | * remain (although with minimal information) so that the target id | ||
| 1592 | * bindings remails. | ||
| 1476 | * | 1593 | * |
| 1477 | * If the remote port is not an FCP Target, it will be fully torn down | 1594 | * If the remote port is not an FCP Target, it will be fully torn down |
| 1478 | * and deallocated, including the fc_remote_port class device. | 1595 | * and deallocated, including the fc_remote_port class device. |
| 1479 | * | 1596 | * |
| 1480 | * If the remote port is an FCP Target, the port structure will be | 1597 | * If the remote port is an FCP Target, the port will be placed in a |
| 1481 | * marked as Not Present, but will remain as long as there is a valid | 1598 | * temporary blocked state. From the LLDD's perspective, the rport no |
| 1482 | * SCSI target id mapping associated with the port structure. Validity | 1599 | * longer exists. From the SCSI midlayer's perspective, the SCSI target |
| 1483 | * is determined by the binding type. If binding by wwpn, then the port | 1600 | * exists, but all sdevs on it are blocked from further I/O. The following |
| 1484 | * structure is always valid and will not be deallocated until the host | 1601 | * is then expected: |
| 1485 | * is removed. If binding by wwnn, then the port structure is valid | 1602 | * If the remote port does not return (signaled by a LLDD call to |
| 1486 | * until another port with the same node name is found in the topology. | 1603 | * fc_remote_port_add()) within the dev_loss_tmo timeout, then the |
| 1487 | * If binding by port id (fc address), then the port structure is valid | 1604 | * scsi target is removed - killing all outstanding i/o and removing the |
| 1488 | * valid until another port with the same address is identified. | 1605 | * scsi devices attached ot it. The port structure will be marked Not |
| 1606 | * Present and be partially cleared, leaving only enough information to | ||
| 1607 | * recognize the remote port relative to the scsi target id binding if | ||
| 1608 | * it later appears. The port will remain as long as there is a valid | ||
| 1609 | * binding (e.g. until the user changes the binding type or unloads the | ||
| 1610 | * scsi host with the binding). | ||
| 1489 | * | 1611 | * |
| 1490 | * Called from interrupt or normal process context. | 1612 | * If the remote port returns within the dev_loss_tmo value (and matches |
| 1613 | * according to the target id binding type), the port structure will be | ||
| 1614 | * reused. If it is no longer a SCSI target, the target will be torn | ||
| 1615 | * down. If it continues to be a SCSI target, then the target will be | ||
| 1616 | * unblocked (allowing i/o to be resumed), and a scan will be activated | ||
| 1617 | * to ensure that all luns are detected. | ||
| 1618 | * | ||
| 1619 | * Called from normal process context only - cannot be called from interrupt. | ||
| 1491 | * | 1620 | * |
| 1492 | * Notes: | 1621 | * Notes: |
| 1493 | * This routine assumes no locks are held on entry. | 1622 | * This routine assumes no locks are held on entry. |
| @@ -1495,53 +1624,20 @@ fc_rport_terminate(struct fc_rport *rport) | |||
| 1495 | void | 1624 | void |
| 1496 | fc_remote_port_delete(struct fc_rport *rport) | 1625 | fc_remote_port_delete(struct fc_rport *rport) |
| 1497 | { | 1626 | { |
| 1498 | struct Scsi_Host *shost = rport_to_shost(rport); | 1627 | int timeout = rport->dev_loss_tmo; |
| 1499 | unsigned long flags; | ||
| 1500 | 1628 | ||
| 1501 | /* If no scsi target id mapping or consistent binding type, delete it */ | 1629 | /* If no scsi target id mapping, delete it */ |
| 1502 | if ((rport->scsi_target_id == -1) || | 1630 | if (rport->scsi_target_id == -1) { |
| 1503 | (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE)) { | ||
| 1504 | fc_rport_terminate(rport); | 1631 | fc_rport_terminate(rport); |
| 1505 | return; | 1632 | return; |
| 1506 | } | 1633 | } |
| 1507 | 1634 | ||
| 1508 | fc_rport_tgt_remove(rport); | 1635 | scsi_target_block(&rport->dev); |
| 1509 | |||
| 1510 | spin_lock_irqsave(shost->host_lock, flags); | ||
| 1511 | list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); | ||
| 1512 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1513 | |||
| 1514 | /* | ||
| 1515 | * Note: We do not remove or clear the hostdata area. This allows | ||
| 1516 | * host-specific target data to persist along with the | ||
| 1517 | * scsi_target_id. It's up to the host to manage it's hostdata area. | ||
| 1518 | */ | ||
| 1519 | 1636 | ||
| 1520 | /* | 1637 | /* cap the length the devices can be blocked until they are deleted */ |
| 1521 | * Reinitialize port attributes that may change if the port comes back. | 1638 | schedule_delayed_work(&rport->dev_loss_work, timeout * HZ); |
| 1522 | */ | ||
| 1523 | rport->maxframe_size = -1; | ||
| 1524 | rport->supported_classes = FC_COS_UNSPECIFIED; | ||
| 1525 | rport->roles = FC_RPORT_ROLE_UNKNOWN; | ||
| 1526 | rport->port_state = FC_PORTSTATE_NOTPRESENT; | ||
| 1527 | 1639 | ||
| 1528 | /* remove the identifiers that aren't used in the consisting binding */ | 1640 | rport->port_state = FC_PORTSTATE_BLOCKED; |
| 1529 | switch (fc_host_tgtid_bind_type(shost)) { | ||
| 1530 | case FC_TGTID_BIND_BY_WWPN: | ||
| 1531 | rport->node_name = -1; | ||
| 1532 | rport->port_id = -1; | ||
| 1533 | break; | ||
| 1534 | case FC_TGTID_BIND_BY_WWNN: | ||
| 1535 | rport->port_name = -1; | ||
| 1536 | rport->port_id = -1; | ||
| 1537 | break; | ||
| 1538 | case FC_TGTID_BIND_BY_ID: | ||
| 1539 | rport->node_name = -1; | ||
| 1540 | rport->port_name = -1; | ||
| 1541 | break; | ||
| 1542 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | ||
| 1543 | break; | ||
| 1544 | } | ||
| 1545 | } | 1641 | } |
| 1546 | EXPORT_SYMBOL(fc_remote_port_delete); | 1642 | EXPORT_SYMBOL(fc_remote_port_delete); |
| 1547 | 1643 | ||
| @@ -1574,127 +1670,140 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) | |||
| 1574 | unsigned long flags; | 1670 | unsigned long flags; |
| 1575 | int create = 0; | 1671 | int create = 0; |
| 1576 | 1672 | ||
| 1577 | rport->roles = roles; | ||
| 1578 | |||
| 1579 | spin_lock_irqsave(shost->host_lock, flags); | 1673 | spin_lock_irqsave(shost->host_lock, flags); |
| 1580 | if ((rport->scsi_target_id == -1) && | 1674 | if (roles & FC_RPORT_ROLE_FCP_TARGET) { |
| 1581 | (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { | 1675 | if (rport->scsi_target_id == -1) { |
| 1582 | rport->scsi_target_id = fc_host->next_target_id++; | 1676 | rport->scsi_target_id = fc_host->next_target_id++; |
| 1583 | create = 1; | 1677 | create = 1; |
| 1678 | } else if (!(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) | ||
| 1679 | create = 1; | ||
| 1584 | } | 1680 | } |
| 1585 | spin_unlock_irqrestore(shost->host_lock, flags); | 1681 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 1586 | 1682 | ||
| 1587 | if (create) | 1683 | rport->roles = roles; |
| 1684 | |||
| 1685 | if (create) { | ||
| 1686 | /* | ||
| 1687 | * There may have been a delete timer running on the | ||
| 1688 | * port. Ensure that it is cancelled as we now know | ||
| 1689 | * the port is an FCP Target. | ||
| 1690 | * Note: we know the rport is exists and in an online | ||
| 1691 | * state as the LLDD would not have had an rport | ||
| 1692 | * reference to pass us. | ||
| 1693 | * | ||
| 1694 | * Take no action on the del_timer failure as the state | ||
| 1695 | * machine state change will validate the | ||
| 1696 | * transaction. | ||
| 1697 | */ | ||
| 1698 | if (!cancel_delayed_work(&rport->dev_loss_work)) | ||
| 1699 | flush_scheduled_work(); | ||
| 1700 | |||
| 1588 | /* initiate a scan of the target */ | 1701 | /* initiate a scan of the target */ |
| 1589 | scsi_queue_work(shost, &rport->scan_work); | 1702 | scsi_queue_work(shost, &rport->scan_work); |
| 1703 | } | ||
| 1590 | } | 1704 | } |
| 1591 | EXPORT_SYMBOL(fc_remote_port_rolechg); | 1705 | EXPORT_SYMBOL(fc_remote_port_rolechg); |
| 1592 | 1706 | ||
| 1593 | /** | 1707 | /** |
| 1594 | * fc_timeout_blocked_rport - Timeout handler for blocked remote port | 1708 | * fc_timeout_deleted_rport - Timeout handler for a deleted remote port that |
| 1595 | * that fails to return in the alloted time. | 1709 | * was a SCSI target (thus was blocked), and failed |
| 1596 | * @data: scsi target that failed to reappear in the alloted time. | 1710 | * to return in the alloted time. |
| 1711 | * | ||
| 1712 | * @data: rport target that failed to reappear in the alloted time. | ||
| 1597 | **/ | 1713 | **/ |
| 1598 | static void | 1714 | static void |
| 1599 | fc_timeout_blocked_rport(void *data) | 1715 | fc_timeout_deleted_rport(void *data) |
| 1600 | { | 1716 | { |
| 1601 | struct fc_rport *rport = (struct fc_rport *)data; | 1717 | struct fc_rport *rport = (struct fc_rport *)data; |
| 1718 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
| 1719 | unsigned long flags; | ||
| 1602 | 1720 | ||
| 1603 | rport->port_state = FC_PORTSTATE_OFFLINE; | 1721 | spin_lock_irqsave(shost->host_lock, flags); |
| 1604 | |||
| 1605 | dev_printk(KERN_ERR, &rport->dev, | ||
| 1606 | "blocked FC remote port time out: removing target\n"); | ||
| 1607 | 1722 | ||
| 1608 | /* | 1723 | /* |
| 1609 | * As this only occurs if the remote port (scsi target) | 1724 | * If the port is ONLINE, then it came back, but was no longer an |
| 1610 | * went away and didn't come back - we'll remove | 1725 | * FCP target. Thus we need to tear down the scsi_target on it. |
| 1611 | * all attached scsi devices. | ||
| 1612 | */ | 1726 | */ |
| 1613 | scsi_target_unblock(&rport->dev); | 1727 | if (rport->port_state == FC_PORTSTATE_ONLINE) { |
| 1614 | scsi_remove_target(&rport->dev); | 1728 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 1615 | } | ||
| 1616 | 1729 | ||
| 1617 | /** | 1730 | dev_printk(KERN_ERR, &rport->dev, |
| 1618 | * fc_remote_port_block - temporarily block any scsi traffic to a remote port. | 1731 | "blocked FC remote port time out: removing target\n"); |
| 1619 | * @rport: remote port to be blocked. | ||
| 1620 | * | ||
| 1621 | * scsi lldd's with a FC transport call this routine to temporarily stop | ||
| 1622 | * all scsi traffic to a remote port. If the port is not a SCSI target, | ||
| 1623 | * no action is taken. If the port is a SCSI target, all attached devices | ||
| 1624 | * are placed into a SDEV_BLOCK state and a timer is started. The timer is | ||
| 1625 | * represents the maximum amount of time the port may be blocked. If the | ||
| 1626 | * timer expires, the port is considered non-existent and the attached | ||
| 1627 | * scsi devices will be removed. | ||
| 1628 | * | ||
| 1629 | * Called from interrupt or normal process context. | ||
| 1630 | * | ||
| 1631 | * Returns zero if successful or error if not | ||
| 1632 | * | ||
| 1633 | * Notes: | ||
| 1634 | * This routine assumes no locks are held on entry. | ||
| 1635 | * | ||
| 1636 | * The timeout and timer types are extracted from the fc transport | ||
| 1637 | * attributes from the caller's rport pointer. | ||
| 1638 | **/ | ||
| 1639 | int | ||
| 1640 | fc_remote_port_block(struct fc_rport *rport) | ||
| 1641 | { | ||
| 1642 | int timeout = rport->dev_loss_tmo; | ||
| 1643 | struct work_struct *work = &rport->dev_loss_work; | ||
| 1644 | 1732 | ||
| 1645 | if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) | 1733 | fc_rport_tgt_remove(rport); |
| 1646 | return -EINVAL; | ||
| 1647 | 1734 | ||
| 1648 | scsi_target_block(&rport->dev); | 1735 | return; |
| 1736 | } | ||
| 1649 | 1737 | ||
| 1650 | /* cap the length the devices can be blocked */ | 1738 | if (rport->port_state != FC_PORTSTATE_BLOCKED) { |
| 1651 | schedule_delayed_work(work, timeout * HZ); | 1739 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 1740 | dev_printk(KERN_ERR, &rport->dev, | ||
| 1741 | "blocked FC remote port time out: leaving target alone\n"); | ||
| 1742 | return; | ||
| 1743 | } | ||
| 1652 | 1744 | ||
| 1653 | rport->port_state = FC_PORTSTATE_BLOCKED; | 1745 | if (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE) { |
| 1654 | return 0; | 1746 | spin_unlock_irqrestore(shost->host_lock, flags); |
| 1655 | } | 1747 | dev_printk(KERN_ERR, &rport->dev, |
| 1656 | EXPORT_SYMBOL(fc_remote_port_block); | 1748 | "blocked FC remote port time out: removing target\n"); |
| 1749 | fc_rport_terminate(rport); | ||
| 1750 | return; | ||
| 1751 | } | ||
| 1657 | 1752 | ||
| 1658 | /** | 1753 | dev_printk(KERN_ERR, &rport->dev, |
| 1659 | * fc_remote_port_unblock - restart any blocked scsi traffic to a remote port. | 1754 | "blocked FC remote port time out: removing target and " |
| 1660 | * @rport: remote port to be unblocked. | 1755 | "saving binding\n"); |
| 1661 | * | 1756 | |
| 1662 | * scsi lld's with a FC transport call this routine to restart IO to all | 1757 | list_move_tail(&rport->peers, &fc_host_rport_bindings(shost)); |
| 1663 | * devices associated with the caller's scsi target following a fc_target_block | ||
| 1664 | * request. Called from interrupt or normal process context. | ||
| 1665 | * | ||
| 1666 | * Notes: | ||
| 1667 | * This routine assumes no locks are held on entry. | ||
| 1668 | **/ | ||
| 1669 | void | ||
| 1670 | fc_remote_port_unblock(struct fc_rport *rport) | ||
| 1671 | { | ||
| 1672 | struct work_struct *work = &rport->dev_loss_work; | ||
| 1673 | struct Scsi_Host *shost = rport_to_shost(rport); | ||
| 1674 | 1758 | ||
| 1675 | /* | 1759 | /* |
| 1676 | * Stop the target timer first. Take no action on the del_timer | 1760 | * Note: We do not remove or clear the hostdata area. This allows |
| 1677 | * failure as the state machine state change will validate the | 1761 | * host-specific target data to persist along with the |
| 1678 | * transaction. | 1762 | * scsi_target_id. It's up to the host to manage it's hostdata area. |
| 1679 | */ | 1763 | */ |
| 1680 | if (!cancel_delayed_work(work)) | ||
| 1681 | flush_scheduled_work(); | ||
| 1682 | 1764 | ||
| 1683 | if (rport->port_state == FC_PORTSTATE_OFFLINE) | 1765 | /* |
| 1684 | /* | 1766 | * Reinitialize port attributes that may change if the port comes back. |
| 1685 | * initiate a scan of the target as the target has | 1767 | */ |
| 1686 | * been torn down. | 1768 | rport->maxframe_size = -1; |
| 1687 | */ | 1769 | rport->supported_classes = FC_COS_UNSPECIFIED; |
| 1688 | scsi_queue_work(shost, &rport->scan_work); | 1770 | rport->roles = FC_RPORT_ROLE_UNKNOWN; |
| 1689 | else | 1771 | rport->port_state = FC_PORTSTATE_NOTPRESENT; |
| 1690 | scsi_target_unblock(&rport->dev); | ||
| 1691 | 1772 | ||
| 1692 | rport->port_state = FC_PORTSTATE_ONLINE; | 1773 | /* remove the identifiers that aren't used in the consisting binding */ |
| 1774 | switch (fc_host_tgtid_bind_type(shost)) { | ||
| 1775 | case FC_TGTID_BIND_BY_WWPN: | ||
| 1776 | rport->node_name = -1; | ||
| 1777 | rport->port_id = -1; | ||
| 1778 | break; | ||
| 1779 | case FC_TGTID_BIND_BY_WWNN: | ||
| 1780 | rport->port_name = -1; | ||
| 1781 | rport->port_id = -1; | ||
| 1782 | break; | ||
| 1783 | case FC_TGTID_BIND_BY_ID: | ||
| 1784 | rport->node_name = -1; | ||
| 1785 | rport->port_name = -1; | ||
| 1786 | break; | ||
| 1787 | case FC_TGTID_BIND_NONE: /* to keep compiler happy */ | ||
| 1788 | break; | ||
| 1789 | } | ||
| 1790 | |||
| 1791 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
| 1792 | |||
| 1793 | /* | ||
| 1794 | * As this only occurs if the remote port (scsi target) | ||
| 1795 | * went away and didn't come back - we'll remove | ||
| 1796 | * all attached scsi devices. | ||
| 1797 | */ | ||
| 1798 | fc_rport_tgt_remove(rport); | ||
| 1693 | } | 1799 | } |
| 1694 | EXPORT_SYMBOL(fc_remote_port_unblock); | ||
| 1695 | 1800 | ||
| 1696 | /** | 1801 | /** |
| 1697 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. | 1802 | * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. |
| 1803 | * | ||
| 1804 | * Will unblock the target (in case it went away and has now come back), | ||
| 1805 | * then invoke a scan. | ||
| 1806 | * | ||
| 1698 | * @data: remote port to be scanned. | 1807 | * @data: remote port to be scanned. |
| 1699 | **/ | 1808 | **/ |
| 1700 | static void | 1809 | static void |
| @@ -1702,6 +1811,7 @@ fc_scsi_scan_rport(void *data) | |||
| 1702 | { | 1811 | { |
| 1703 | struct fc_rport *rport = (struct fc_rport *)data; | 1812 | struct fc_rport *rport = (struct fc_rport *)data; |
| 1704 | 1813 | ||
| 1814 | scsi_target_unblock(&rport->dev); | ||
| 1705 | scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, | 1815 | scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, |
| 1706 | SCAN_WILD_CARD, 1); | 1816 | SCAN_WILD_CARD, 1); |
| 1707 | } | 1817 | } |
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 4496b32972e5..319ff7a60dfe 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #define SCSI_TRANSPORT_FC_H | 28 | #define SCSI_TRANSPORT_FC_H |
| 29 | 29 | ||
| 30 | #include <linux/config.h> | 30 | #include <linux/config.h> |
| 31 | #include <scsi/scsi.h> | ||
| 31 | 32 | ||
| 32 | struct scsi_transport_template; | 33 | struct scsi_transport_template; |
| 33 | 34 | ||
| @@ -429,6 +430,34 @@ struct fc_function_template { | |||
| 429 | }; | 430 | }; |
| 430 | 431 | ||
| 431 | 432 | ||
| 433 | /** | ||
| 434 | * fc_remote_port_chkready - called to validate the remote port state | ||
| 435 | * prior to initiating io to the port. | ||
| 436 | * | ||
| 437 | * Returns a scsi result code that can be returned by the LLDD. | ||
| 438 | * | ||
| 439 | * @rport: remote port to be checked | ||
| 440 | **/ | ||
| 441 | static inline int | ||
| 442 | fc_remote_port_chkready(struct fc_rport *rport) | ||
| 443 | { | ||
| 444 | int result; | ||
| 445 | |||
| 446 | switch (rport->port_state) { | ||
| 447 | case FC_PORTSTATE_ONLINE: | ||
| 448 | result = 0; | ||
| 449 | break; | ||
| 450 | case FC_PORTSTATE_BLOCKED: | ||
| 451 | result = DID_BUS_BUSY << 16; | ||
| 452 | break; | ||
| 453 | default: | ||
| 454 | result = DID_NO_CONNECT << 16; | ||
| 455 | break; | ||
| 456 | } | ||
| 457 | return result; | ||
| 458 | } | ||
| 459 | |||
| 460 | |||
| 432 | struct scsi_transport_template *fc_attach_transport( | 461 | struct scsi_transport_template *fc_attach_transport( |
| 433 | struct fc_function_template *); | 462 | struct fc_function_template *); |
| 434 | void fc_release_transport(struct scsi_transport_template *); | 463 | void fc_release_transport(struct scsi_transport_template *); |
| @@ -437,8 +466,6 @@ struct fc_rport *fc_remote_port_add(struct Scsi_Host *shost, | |||
| 437 | int channel, struct fc_rport_identifiers *ids); | 466 | int channel, struct fc_rport_identifiers *ids); |
| 438 | void fc_remote_port_delete(struct fc_rport *rport); | 467 | void fc_remote_port_delete(struct fc_rport *rport); |
| 439 | void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles); | 468 | void fc_remote_port_rolechg(struct fc_rport *rport, u32 roles); |
| 440 | int fc_remote_port_block(struct fc_rport *rport); | ||
| 441 | void fc_remote_port_unblock(struct fc_rport *rport); | ||
| 442 | int scsi_is_fc_rport(const struct device *); | 469 | int scsi_is_fc_rport(const struct device *); |
| 443 | 470 | ||
| 444 | static inline u64 wwn_to_u64(u8 *wwn) | 471 | static inline u64 wwn_to_u64(u8 *wwn) |
