Re: [v2 PATCH 4/5] bnx2fc: Broadcom FCoE Offload driver submission - part 2

Bhanu Gollapudi
2011-01-18T03:29:43Z

On Mon, 2011-01-17 at 18:44 -0800, Mike Christie wrote:
> On 12/24/2010 12:02 AM, Bhanu Gollapudi wrote:
> > diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
>
> > +
> > +static void bnx2fc_offload_session(struct bnx2fc_port *port,
> > + struct bnx2fc_rport *tgt,
> > + struct fc_rport_priv *rdata)
> > +{
> > + struct fc_lport *lport = rdata->local_port;
> > + struct fc_rport *rport = rdata->rport;
> > + struct bnx2fc_hba *hba = port->hba;
> > + int rval;
> > + int i = 0;
> > +
> > + /* Initialize bnx2fc_rport */
> > + /* NOTE: tgt is already bzero'd */
> > + rval = bnx2fc_init_tgt(tgt, port, rdata);
> > + if (rval) {
> > + printk(KERN_ERR PFX "Failed to allocate conn id for "
> > + "port_id (%6x)\n", rport->port_id);
> > + goto ofld_err;
> > + }
> > +
> > + if (hba->num_ofld_sess>= BNX2FC_NUM_MAX_SESS) {
> > + printk(KERN_ERR PFX "exceeded max sessions port_id (%6x)\n",
> > + rport->port_id);
> > + goto ofld_err;
> > + }
> > +
> > + /* Allocate session resources */
> > + rval = bnx2fc_alloc_session_resc(hba, tgt);
> > + if (rval) {
> > + printk(KERN_ERR PFX "Failed to allocate resources\n");
> > + goto ofld_err;
> > + }
> > +
> > + /*
> > + * Initialize FCoE session offload process.
> > + * Upon completion of offload process add
> > + * rport to list of rports
> > + */
> > +retry_ofld:
> > + clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL,&tgt->flags);
> > + rval = bnx2fc_send_session_ofld_req(port, tgt);
> > + if (rval) {
> > + printk(KERN_ERR PFX "ofld_req failed\n");
> > + goto ofld_err;
> > + }
> > +
> > + /*
> > + * wait for the session is offloaded and enabled. 20 Secs
> > + * should be ample time for this process to complete.
> > + */
> > + init_timer(&tgt->ofld_timer);
> > + tgt->ofld_timer.expires = (20 * HZ) + jiffies;
> > + tgt->ofld_timer.function = bnx2fc_ofld_timer;
> > + tgt->ofld_timer.data = (unsigned long)tgt;
>
>
> setup_timer()

OK. will use. Is there any advantage of using setup_timer()? This is not
a perf path.

>
> > +
> > + add_timer(&tgt->ofld_timer);
> > +
> > + wait_event_interruptible(tgt->ofld_wait,
> > + (test_bit(
> > + BNX2FC_FLAG_OFLD_REQ_CMPL,
> > + &tgt->flags)));
>
>
>
> This gets run from libfc's work queue, right? It does not seem nice to
> sleep here for so long and block other drivers.

> For multipath setups having to wait this longs would be very bad.

20 secs sounds long. But this is a local completion with the FW which
hardly takes any time.

>
>
> > +
> > +void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt)
> > +{
> > + struct bnx2fc_cmd *io_req;
> > + struct list_head *list;
> > + struct list_head *tmp;
> > + int rc;
> > + int i = 0;
> > + bnx2fc_dbg(LOG_IOERR, "Entered flush_active_ios - %d, port_id = 0x%x\n",
> > + tgt->num_active_ios, tgt->rdata->ids.port_id);
> > +
> > + spin_lock_bh(&tgt->tgt_lock);
> > + tgt->flush_in_prog = 1;
> > +
> > + list_for_each_safe(list, tmp,&tgt->active_cmd_queue) {
> > + i++;
> > + io_req = (struct bnx2fc_cmd *)list;
> > + list_del_init(&io_req->link);
> > + io_req->on_active_queue = 0;
> > + bnx2fc_dbg(LOG_IOERR, "cmd_queue cleanup - xid = 0x%x ref_cnt ="
> > + " %d\n", io_req->xid, io_req->cmd_refcnt.counter);
> > +
> > + if (cancel_delayed_work(&io_req->timeout_work)) {
> > + if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT,
> > + &io_req->req_flags)) {
> > + /* Handle eh_abort timeout */
> > + bnx2fc_dbg(LOG_IOERR, "eh_abort for IO "
> > + "with oxid = 0x%x "
> > + "cleaned up\n", io_req->xid);
> > + complete(&io_req->tm_done);
> > + }
> > + bnx2fc_cmd_release(io_req); /* drop timer hold */
> > + }
> > +
> > + set_bit(BNX2FC_FLAG_IO_COMPL,&io_req->req_flags);
> > + set_bit(BNX2FC_FLAG_IO_CLEANUP,&io_req->req_flags);
> > + rc = bnx2fc_initiate_cleanup(io_req);
> > + BUG_ON(rc);
> > + }
> > +
> > + list_for_each_safe(list, tmp,&tgt->els_queue) {
> > + i++;
> > + io_req = (struct bnx2fc_cmd *)list;
> > + list_del_init(&io_req->link);
> > + io_req->on_active_queue = 0;
> > +
> > + bnx2fc_dbg(LOG_IOERR, "els_queue cleanup - xid = 0x%x"
> > + " ref_cnt = %d\n", io_req->xid,
> > + io_req->cmd_refcnt.counter);
> > +
> > + if (cancel_delayed_work(&io_req->timeout_work))
> > + bnx2fc_cmd_release(io_req); /* drop timer hold */
> > +
> > + if ((io_req->cb_func)&& (io_req->cb_arg)) {
> > + io_req->cb_func(io_req->cb_arg);
> > + io_req->cb_arg = NULL;
> > + }
> > +
> > + rc = bnx2fc_initiate_cleanup(io_req);
> > + BUG_ON(rc);
> > + }
> > +
> > + list_for_each_safe(list, tmp,&tgt->io_retire_queue) {
> > + i++;
> > + io_req = (struct bnx2fc_cmd *)list;
> > + list_del_init(&io_req->link);
> > +
> > + bnx2fc_dbg(LOG_IOERR, "retire_queue flush - xid = 0x%x"
> > + " ref_cnt = %d\n", io_req->xid,
> > + io_req->cmd_refcnt.counter);
> > +
> > + if (cancel_delayed_work(&io_req->timeout_work))
> > + bnx2fc_cmd_release(io_req);
> > +
> > + clear_bit(BNX2FC_FLAG_ISSUE_RRQ,&io_req->req_flags);
> > + }
> > +
> > + bnx2fc_dbg(LOG_IOERR, "IOs flushed = %d\n", i);
> > + i = 0;
> > + spin_unlock_bh(&tgt->tgt_lock);
> > + /* wait for active_ios to go to 0 */
> > + while ((tgt->num_active_ios != 0)&& (i++< 120))
> > + msleep(25);
>
>
> Are you waiting for bnx2fc_cmd_timeout to stop running (for the case
> where the cancel did not indicate it was pending) or to get a response
> to when you did bnx2fc_initiate_cleanup?

Waiting to get the response for bnx2fc_initiate_cleanup().

>
> For bnx2fc_cmd_timeout you should just flush the workqueue_struct.
>
> For bnx2fc_initiate_cleanup, where did the 120 * 25msecs limit come from?

This is again a local completion from FW to get the cleanup completion
for the outstanding IOs, and should not take longer. I'll probably use a
symbol instead of hard coded 120.

>
>
>
> > + if (tgt->num_active_ios != 0)
> > + printk(KERN_ERR PFX "CLEANUP on port 0x%x:"
> > + " active_ios = %d\n",
> > + tgt->rdata->ids.port_id, tgt->num_active_ios);
> > + spin_lock_bh(&tgt->tgt_lock);
> > + tgt->flush_in_prog = 0;
> > + spin_unlock_bh(&tgt->tgt_lock);
> > +}
> > +
> > +static void bnx2fc_upload_session(struct bnx2fc_port *port,
> > + struct bnx2fc_rport *tgt)
> > +{
> > + struct bnx2fc_hba *hba = port->hba;
> > +
> > + bnx2fc_dbg(LOG_SESS, "upload_session: active_ios = %d\n",
> > + tgt->num_active_ios);
> > +
> > + /*
> > + * Called with hba->hba_mutex held.
> > + * This is a blocking call
> > + */
> > + clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL,&tgt->flags);
> > + bnx2fc_send_session_disable_req(port, tgt);
> > +
> > + /*
> > + * wait for upload to complete. 20 Secs
> > + * should be sufficient time for this process to complete.
> > + */
> > + init_timer(&tgt->upld_timer);
> > + tgt->upld_timer.expires = (20 * HZ) + jiffies;
> > + tgt->upld_timer.function = bnx2fc_upld_timer;
> > + tgt->upld_timer.data = (unsigned long)tgt;
> > +
>
>
> setup_timer() Check for other places in the code for this.

Yes. will do.

>
>
> > + add_timer(&tgt->upld_timer);
> > +
> > + bnx2fc_dbg(LOG_SESS, "waiting for disable compl\n");
> > + wait_event_interruptible(tgt->upld_wait,
> > + (test_bit(
> > + BNX2FC_FLAG_UPLD_REQ_COMPL,
> > + &tgt->flags)));
> > +
> > + if (signal_pending(current))
> > + flush_signals(current);
> > +
> > + del_timer_sync(&tgt->upld_timer);
> > +
> > + bnx2fc_dbg(LOG_SESS, "disable wait complete flags = 0x%lx\n",
> > + tgt->flags);
> > +
> > + /*
> > + * traverse thru the active_q and tmf_q and cleanup
> > + * IOs in these lists
> > + */
> > + bnx2fc_dbg(LOG_SESS, "flush/upload\n");
> > + bnx2fc_flush_active_ios(tgt);
> > +
> > + /* Issue destroy KWQE */
> > + if (test_bit(BNX2FC_FLAG_DISABLED,&tgt->flags)) {
> > + bnx2fc_dbg(LOG_SESS, "send destroy req\n");
> > + clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL,&tgt->flags);
> > + bnx2fc_send_session_destroy_req(hba, tgt);
> > +
> > + /* wait for destroy to complete */
> > + init_timer(&tgt->upld_timer);
> > + tgt->upld_timer.expires = (20 * HZ) + jiffies;
> > + tgt->upld_timer.function = bnx2fc_upld_timer;
> > + tgt->upld_timer.data = (unsigned long)tgt;
> > +
> > + add_timer(&tgt->upld_timer);
> > +
> > + wait_event_interruptible(tgt->upld_wait,
> > + (test_bit(
> > + BNX2FC_FLAG_UPLD_REQ_COMPL,
> > + &tgt->flags)));
> > +
> > + if (!(test_bit(BNX2FC_FLAG_DESTROYED,&tgt->flags)))
> > + printk(KERN_ERR PFX "ERROR!! destroy timed out\n");
> > +
> > + bnx2fc_dbg(LOG_SESS, "destroy wait complete flags = 0x%lx\n",
> > + tgt->flags);
> > + if (signal_pending(current))
> > + flush_signals(current);
> > +
> > + del_timer_sync(&tgt->upld_timer);
> > +
> > + } else {
> > + printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy"
> > + " not sent to FW\n");
> > + }
>
>
> No need for extra brackets.

OK.

>
> > +
> > +
> > + /* Free session resources */
> > + spin_lock_bh(&tgt->cq_lock);
> > + bnx2fc_free_session_resc(hba, tgt);
> > + bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
> > + spin_unlock_bh(&tgt->cq_lock);
> > + return;
>
> extra return

OK.

>
>
> > +/**
> > + * bnx2fc_tgt_lookup() - Lookup a bnx2fc_rport by port_id
> > + * @port: bnx2fc_port struct to lookup the target port on
> > + * @port_id: The remote port ID to look up
> > + */
> > +struct bnx2fc_rport *bnx2fc_tgt_lookup(struct bnx2fc_port *port,
> > + u32 port_id)
> > +{
> > + struct bnx2fc_hba *hba = port->hba;
> > + struct bnx2fc_rport *tgt;
> > + struct fc_rport_priv *rdata;
> > + int i;
> > +
> > + for (i = 0; i< BNX2FC_NUM_MAX_SESS; i++) {
> > + tgt = hba->tgt_ofld_list[i];
> > + if ((tgt)&& (tgt->port == port)) {
> > + rdata = tgt->rdata;
> > + if (rdata->ids.port_id == port_id) {
> > + if (rdata->rp_state != RPORT_ST_DELETE) {
> > + bnx2fc_dbg(LOG_IOERR, "rport 0x%x "
> > + "obtained\n",
> > + rdata->ids.port_id);
> > + return tgt;
> > + } else {
> > + printk(KERN_ERR PFX "rport 0x%x "
> > + "is in DELETED state\n",
> > + rdata->ids.port_id);
> > + return NULL;
> > + }
> > + }
> > + }
> > + }
> > + return NULL;
> > +}
>
>
> It seems this should go in scsi_transport_fc. I thought there was a
> similar lookup function in libfc too, and we were trying to move that to
> the transport class.

this is bnx2fc driver specific lookup, looking if the target is
offloaded or not.

>
>
>
>
> > +
> > +
> > +/**
> > + * bnx2fc_alloc_conn_id - allocates FCOE Connection id
> > + *
> > + * @hba: pointer to adapter structure
> > + * @tgt: pointer to bnx2fc_rport structure
> > + */
> > +static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba,
> > + struct bnx2fc_rport *tgt)
> > +{
> > + u32 conn_id, next;
> > +
> > + /* called with hba mutex held */
> > +
> > + /*
> > + * tgt_ofld_list access is synchronized using
> > + * both hba mutex and hba lock. Atleast hba mutex or
> > + * hba lock needs to be held for read access.
> > + */
> > +
> > + spin_lock_bh(&hba->hba_lock);
> > + next = hba->next_conn_id;
> > + conn_id = hba->next_conn_id++;
> > + if (hba->next_conn_id == BNX2FC_NUM_MAX_SESS)
> > + hba->next_conn_id = 0;
> > +
> > + while (hba->tgt_ofld_list[conn_id] != NULL) {
> > + conn_id++;
> > + if (conn_id == BNX2FC_NUM_MAX_SESS)
> > + conn_id = 0;
> > +
> > + if (conn_id == next) {
> > + /* No free conn_ids are available */
> > + conn_id = -1;
> > + return conn_id;
>
> Just do return -1;

OK.

>
>
>
>
> > +static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba,
> > + struct bnx2fc_rport *tgt)
> > +{
> > + dma_addr_t page;
> > + int num_pages;
> > + u32 *pbl;
> > +
> > + /* Allocate and map SQ */
> > + tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE;
> > + tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1))& PAGE_MASK;
> > +
> > + tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size,
> > + &tgt->sq_dma, GFP_KERNEL);
> > + if (!tgt->sq) {
> > + printk(KERN_ALERT PFX "unable to allocate SQ memory %d\n",
> > + tgt->sq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->sq, 0, tgt->sq_mem_size);
> > +
> > + /* Allocate and map CQ */
> > + tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE;
> > + tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1))& PAGE_MASK;
> > +
> > + tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size,
> > + &tgt->cq_dma, GFP_KERNEL);
> > + if (!tgt->cq) {
> > + printk(KERN_ALERT PFX "unable to allocate CQ memory %d\n",
> > + tgt->cq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->cq, 0, tgt->cq_mem_size);
> > +
> > + /* Allocate and map RQ and RQ PBL */
> > + tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE;
> > + tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1))& PAGE_MASK;
> > +
> > + tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size,
> > + &tgt->rq_dma, GFP_KERNEL);
> > + if (!tgt->rq) {
> > + printk(KERN_ALERT PFX "unable to allocate RQ memory %d\n",
> > + tgt->rq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->rq, 0, tgt->rq_mem_size);
> > +
> > + tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *);
> > + tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1))& PAGE_MASK;
> > +
> > + tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size,
> > + &tgt->rq_pbl_dma, GFP_KERNEL);
> > + if (!tgt->rq_pbl) {
> > + printk(KERN_ALERT PFX "unable to allocate RQ PBL %d\n",
> > + tgt->rq_pbl_size);
> > + goto mem_alloc_failure;
> > + }
> > +
> > + memset(tgt->rq_pbl, 0, tgt->rq_pbl_size);
> > + num_pages = tgt->rq_mem_size / PAGE_SIZE;
> > + page = tgt->rq_dma;
> > + pbl = (u32 *)tgt->rq_pbl;
> > +
>
>
> What is the code below supposed to be doing?

It is just filling the PBL (aka, buffer descriptor list) for RQ.

>
>
> > + while (num_pages--) {
> > + *pbl = (u32)page;
> > + pbl++;
> > + *pbl = (u32)((u64)page>> 32);
> > + pbl++;
> > + page += PAGE_SIZE;
> > + }
> > +
> > + /* Allocate and map XFERQ */
> > + tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE;
> > + tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1))&
> > + PAGE_MASK;
> > +
> > + tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size,
> > + &tgt->xferq_dma, GFP_KERNEL);
> > + if (!tgt->xferq) {
> > + printk(KERN_ALERT PFX "unable to allocate XFERQ %d\n",
> > + tgt->xferq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->xferq, 0, tgt->xferq_mem_size);
> > +
> > + /* Allocate and map CONFQ& CONFQ PBL */
> > + tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE;
> > + tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1))&
> > + PAGE_MASK;
> > +
> > + tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size,
> > + &tgt->confq_dma, GFP_KERNEL);
> > + if (!tgt->confq) {
> > + printk(KERN_ALERT PFX "unable to allocate CONFQ %d\n",
> > + tgt->confq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->confq, 0, tgt->confq_mem_size);
> > +
> > + tgt->confq_pbl_size =
> > + (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *);
> > + tgt->confq_pbl_size =
> > + (tgt->confq_pbl_size + (PAGE_SIZE - 1))& PAGE_MASK;
> > +
> > + tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev,
> > + tgt->confq_pbl_size,
> > + &tgt->confq_pbl_dma, GFP_KERNEL);
> > + if (!tgt->confq_pbl) {
> > + printk(KERN_ALERT PFX "unable to allocate CONFQ PBL %d\n",
> > + tgt->confq_pbl_size);
> > + goto mem_alloc_failure;
> > + }
> > +
> > + memset(tgt->confq_pbl, 0, tgt->confq_pbl_size);
> > + num_pages = tgt->confq_mem_size / PAGE_SIZE;
> > + page = tgt->confq_dma;
> > + pbl = (u32 *)tgt->confq_pbl;
> > +
> > + while (num_pages--) {
> > + *pbl = (u32)page;
> > + pbl++;
> > + *pbl = (u32)((u64)page>> 32);
> > + pbl++;
> > + page += PAGE_SIZE;
> > + }
> > +
> > + /* Allocate and map ConnDB */
> > + tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db);
> > +
> > + tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev,
> > + tgt->conn_db_mem_size,
> > + &tgt->conn_db_dma, GFP_KERNEL);
> > + if (!tgt->conn_db) {
> > + printk(KERN_ALERT PFX "unable to allocate conn_db %d\n",
> > + tgt->conn_db_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->conn_db, 0, tgt->conn_db_mem_size);
> > +
> > +
> > + /* Allocate and map LCQ */
> > + tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE;
> > + tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1))&
> > + PAGE_MASK;
> > +
> > + tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size,
> > + &tgt->lcq_dma, GFP_KERNEL);
> > +
> > + if (!tgt->lcq) {
> > + printk(KERN_ALERT PFX "unable to allocate lcq %d\n",
> > + tgt->lcq_mem_size);
> > + goto mem_alloc_failure;
> > + }
> > + memset(tgt->lcq, 0, tgt->lcq_mem_size);
> > +
> > + /* Arm CQ */
> > + tgt->conn_db->cq_arm.lo = -1;
> > + tgt->conn_db->rq_prod = 0x8000;
> > +
> > + return 0;
> > +
> > +mem_alloc_failure:
> > + bnx2fc_free_session_resc(hba, tgt);
> > + bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id);
> > + return -ENOMEM;
> > +}
> > +
>

Thanks again for your valuable comments, Mike.

Regards,
Bhanu