aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc
diff options
context:
space:
mode:
authorJames.Smart@Emulex.Com <James.Smart@Emulex.Com>2005-10-18 12:03:35 -0400
committerJames Bottomley <jejb@mulgrave.(none)>2005-10-28 22:20:07 -0400
commit19a7b4aebf9ad435c69a7e39930338499af4d152 (patch)
tree6d1c4cbc822009c8facb219dcd955d52070655d1 /drivers/scsi/lpfc
parent422c0d61d591cbfb70f029e13505fb437e169d68 (diff)
[SCSI] update fc_transport for removal of block/unblock functions
We recently went back to implement a board reset. When we perform the reset, we wanted to tear down the internal data structures and rebuild them. Unfortunately, when it came to the rport structure, things were odd. If we deleted them, the scsi targets and sdevs would be torn down. Not a good thing for a temporary reset. We could block the rports, but we either maintain the internal structures to keep the rport reference (perhaps even replicating what's in the transport), or we have to fatten the fc transport with new search routines to find the rport (and deal with a case of a dangling rport that the driver forgets). It dawned on me that we had actually reached this state incorrectly. When the fc transport first started, we did the block/unblock first, then added the rport interface. The purpose of block/unblock is to hide the temporary disappearance of the rport (e.g. being deleted, then readded). Why are we making the driver do the block/unblock ? We should be making the transport have only an rport add/delete, and the let the transport handle the block/unblock. So... This patch removes the existing fc_remote_port_block/unblock functions. It moves the block/unblock functionality into the fc_remote_port_add/delete functions. Updates for the lpfc driver are included. Qlogic driver updates are also enclosed, thanks to the contributions of Andrew Vasquez. [Note: the qla2xxx changes are relative to the scsi-misc-2.6 tree as of this morning - which does not include the recent patches sent by Andrew]. The zfcp driver does not use the block/unblock functions. One last comment: The resulting behavior feels very clean. The LLDD is concerned only with add/delete, which corresponds to the physical disappearance. However, the fact that the scsi target and sdevs are not immediately torn down after the LLDD calls delete causes an interesting scenario... the midlayer can call the xxx_slave_alloc and xxx_queuecommand functions with a sdev that is at the location the rport used to be. The driver must validate the device exists when it first enters these functions. In thinking about it, this has always been the case for the LLDD and these routines. The existing drivers already check for existence. However, this highlights that simple validation via data structure dereferencing needs to be watched. To deal with this, a new transport function, fc_remote_port_chkready() was created that LLDDs should call when they first enter these two routines. It validates the rport state, and returns a scsi result which could be returned. In addition to solving the above, it also creates consistent behavior from the LLDD's when the block and deletes are occuring. Rejections fixed up and Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/lpfc')
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c28
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c83
3 files changed, 37 insertions, 93 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
1053static void
1054lpfc_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
1163lpfc_slave_alloc(struct scsi_device *sdev) 1142lpfc_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