From 19a7b4aebf9ad435c69a7e39930338499af4d152 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Tue, 18 Oct 2005 12:03:35 -0400 Subject: [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 --- drivers/scsi/lpfc/lpfc_hbadisc.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') 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, if (ndlp->nlp_type & NLP_FCP_INITIATOR) rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; + scsi_block_requests(phba->host); ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); if (!rport) { dev_printk(KERN_WARNING, &phba->pcidev->dev, @@ -1044,6 +1045,23 @@ lpfc_register_remote_port(struct lpfc_hba * phba, } rdata = rport->dd_data; rdata->pnode = ndlp; + scsi_unblock_requests(phba->host); + + return; +} + +static void +lpfc_unregister_remote_port(struct lpfc_hba * phba, + struct lpfc_nodelist * ndlp) +{ + struct fc_rport *rport = ndlp->rport; + struct lpfc_rport_data *rdata = rport->dd_data; + + ndlp->rport = NULL; + rdata->pnode = NULL; + scsi_block_requests(phba->host); + fc_remote_port_delete(rport); + scsi_unblock_requests(phba->host); return; } @@ -1260,7 +1278,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) * may have removed the remote port. */ if ((rport_del != none) && nlp->rport) - fc_remote_port_block(nlp->rport); + lpfc_unregister_remote_port(phba, nlp); if (rport_add != none) { /* @@ -1270,8 +1288,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) */ if (!nlp->rport) lpfc_register_remote_port(phba, nlp); - else - fc_remote_port_unblock(nlp->rport); /* * if we added to Mapped list, but the remote port @@ -1490,7 +1506,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) LPFC_MBOXQ_t *mb; LPFC_MBOXQ_t *nextmb; struct lpfc_dmabuf *mp; - struct fc_rport *rport; /* Cleanup node for NPort */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, @@ -1507,10 +1522,7 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * and flush cache's w/o generating flush errors. */ if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { - rport = ndlp->rport; - ndlp->rport = NULL; - fc_remote_port_unblock(rport); - fc_remote_port_delete(rport); + lpfc_unregister_remote_port(phba, ndlp); ndlp->nlp_sid = NLP_NO_SID; } -- cgit v1.2.2 From 21568f5387636fe2bfb9ee42383d76de11ed99c7 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Fri, 28 Oct 2005 20:29:36 -0400 Subject: [SCSI] lpfc: Remove RPI hash from the driver Table was not providing a lot of value and injected a couple of errors. Removed it and made functionality inline. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 87 +++++++--------------------------------- 1 file changed, 15 insertions(+), 72 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 6c846ad373bc..cd06d4c471ac 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -890,10 +890,7 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -981,10 +978,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -1488,7 +1482,6 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) if (rc == MBX_NOT_FINISHED) mempool_free( mbox, phba->mbox_mem_pool); } - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); lpfc_no_rpi(phba, ndlp); ndlp->nlp_rpi = 0; return 1; @@ -2434,10 +2427,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) pmb->context1 = NULL; - if (ndlp->nlp_rpi != 0) - lpfc_findnode_remove_rpi(phba, ndlp->nlp_rpi); ndlp->nlp_rpi = mb->un.varWords[0]; - lpfc_addnode_rpi(phba, ndlp, ndlp->nlp_rpi); ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_state = NLP_STE_UNMAPPED_NODE; lpfc_nlp_list(phba, ndlp, NLP_UNMAPPED_LIST); @@ -2463,75 +2453,28 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) } /* - * This routine looks up the ndlp hash - * table for the given RPI. If rpi found + * This routine looks up the ndlp lists + * for the given RPI. If rpi found * it return the node list pointer - * else return 0. + * else return NULL. */ struct lpfc_nodelist * lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) { - struct lpfc_nodelist *ret; - - ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)]; - while ((ret != 0) && (ret->nlp_rpi != rpi)) { - ret = ret->nlp_rpi_hash_next; - } - return ret; -} - -/* - * This routine looks up the ndlp hash table for the - * given RPI. If rpi found it return the node list - * pointer else return 0 after deleting the entry - * from hash table. - */ -struct lpfc_nodelist * -lpfc_findnode_remove_rpi(struct lpfc_hba * phba, uint16_t rpi) -{ - struct lpfc_nodelist *ret, *temp;; - - ret = phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)]; - if (ret == 0) - return NULL; - - if (ret->nlp_rpi == rpi) { - phba->fc_nlplookup[LPFC_RPI_HASH_FUNC(rpi)] = - ret->nlp_rpi_hash_next; - ret->nlp_rpi_hash_next = NULL; - return ret; - } - - while ((ret->nlp_rpi_hash_next != 0) && - (ret->nlp_rpi_hash_next->nlp_rpi != rpi)) { - ret = ret->nlp_rpi_hash_next; - } - - if (ret->nlp_rpi_hash_next != 0) { - temp = ret->nlp_rpi_hash_next; - ret->nlp_rpi_hash_next = temp->nlp_rpi_hash_next; - temp->nlp_rpi_hash_next = NULL; - return temp; - } else { - return NULL; - } -} - -/* - * This routine adds the node list entry to the - * ndlp hash table. - */ -void -lpfc_addnode_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, - uint16_t rpi) -{ + struct lpfc_nodelist *ndlp; + struct list_head * lists[]={&phba->fc_nlpunmap_list, + &phba->fc_nlpmap_list, + &phba->fc_plogi_list, + &phba->fc_adisc_list, + &phba->fc_reglogin_list}; + int i; - uint32_t index; + for (i = 0; i < ARRAY_SIZE(lists); i++ ) + list_for_each_entry(ndlp, lists[i], nlp_listp) + if (ndlp->nlp_rpi == rpi) + return (ndlp); - index = LPFC_RPI_HASH_FUNC(rpi); - ndlp->nlp_rpi_hash_next = phba->fc_nlplookup[index]; - phba->fc_nlplookup[index] = ndlp; - return; + return NULL; } void -- cgit v1.2.2 From 604a3e3042eb89ffaa4f735ef9208281aae786c7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 29 Oct 2005 10:28:33 -0500 Subject: [SCSI] lpfc: Fix for "command completion for iotax x?? not found" From: James Smart There were scenarios where the error handlers could reuse an iotag value of an active io. Remove all possibility of this by pre-assigning iotag resources to command resources. Signed-off-by: James Smart Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index cd06d4c471ac..259eeb161b82 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1445,10 +1445,9 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) iocb, iocb); spin_lock_irq(phba->host-> host_lock); - } else { - list_add_tail(&iocb->list, - &phba->lpfc_iocb_list); - } + } else + lpfc_sli_release_iocbq(phba, + iocb); } } spin_unlock_irq(phba->host->host_lock); -- cgit v1.2.2