diff options
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_io.c')
| -rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 442 |
1 files changed, 332 insertions, 110 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index b5b5c346d77..7bc47fc7c68 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1,7 +1,7 @@ /* bnx2fc_io.c: Broadcom NetXtreme II Linux FCoE offload driver. * IO manager and SCSI IO processing. * - * Copyright (c) 2008 - 2010 Broadcom Corporation + * Copyright (c) 2008 - 2013 Broadcom Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,9 +17,7 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, int bd_index); static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); -static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req); -static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, - struct bnx2fc_cmd *io_req); +static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req); static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req); static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req); static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, @@ -29,10 +27,11 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req, unsigned int timer_msec) { - struct bnx2fc_hba *hba = io_req->port->priv; + struct bnx2fc_interface *interface = io_req->port->priv; - if (queue_delayed_work(hba->timer_work_queue, &io_req->timeout_work, - msecs_to_jiffies(timer_msec))) + if (queue_delayed_work(interface->timer_work_queue, + &io_req->timeout_work, + msecs_to_jiffies(timer_msec))) kref_get(&io_req->refcount); } @@ -217,6 +216,11 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code) return; BNX2FC_IO_DBG(io_req, "scsi_done. err_code = 0x%x\n", err_code); + if (test_bit(BNX2FC_FLAG_CMD_LOST, &io_req->req_flags)) { + /* Do not call scsi done for this IO */ + return; + } + bnx2fc_unmap_sg_list(io_req); io_req->sc_cmd = NULL; if (!sc_cmd) { @@ -235,8 +239,7 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code) sc_cmd->scsi_done(sc_cmd); } -struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, - u16 min_xid, u16 max_xid) +struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) { struct bnx2fc_cmd_mgr *cmgr; struct io_bdt *bdt_info; @@ -248,6 +251,8 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, int num_ios, num_pri_ios; size_t bd_tbl_sz; int arr_sz = num_possible_cpus() + 1; + u16 min_xid = BNX2FC_MIN_XID; + u16 max_xid = hba->max_xid; if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \ @@ -277,6 +282,8 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, arr_sz, GFP_KERNEL); if (!cmgr->free_list_lock) { printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); + kfree(cmgr->free_list); + cmgr->free_list = NULL; goto mem_err; } @@ -294,7 +301,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, * of slow path requests. */ xid = BNX2FC_MIN_XID; - num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS; + num_pri_ios = num_ios - hba->elstm_xids; for (i = 0; i < num_ios; i++) { io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); @@ -363,7 +370,7 @@ void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr) struct bnx2fc_hba *hba = cmgr->hba; size_t bd_tbl_sz; u16 min_xid = BNX2FC_MIN_XID; - u16 max_xid = BNX2FC_MAX_XID; + u16 max_xid = hba->max_xid; int num_ios; int i; @@ -401,11 +408,10 @@ free_cmd_pool: goto free_cmgr; for (i = 0; i < num_possible_cpus() + 1; i++) { - struct list_head *list; - struct list_head *tmp; + struct bnx2fc_cmd *tmp, *io_req; - list_for_each_safe(list, tmp, &cmgr->free_list[i]) { - struct bnx2fc_cmd *io_req = (struct bnx2fc_cmd *)list; + list_for_each_entry_safe(io_req, tmp, + &cmgr->free_list[i], link) { list_del(&io_req->link); kfree(io_req); } @@ -419,12 +425,13 @@ free_cmgr: struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) { struct fcoe_port *port = tgt->port; - struct bnx2fc_hba *hba = port->priv; - struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr; struct bnx2fc_cmd *io_req; struct list_head *listp; struct io_bdt *bd_tbl; int index = RESERVE_FREE_LIST_INDEX; + u32 free_sqes; u32 max_sqes; u16 xid; @@ -445,8 +452,10 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) * cmgr lock */ spin_lock_bh(&cmd_mgr->free_list_lock[index]); + free_sqes = atomic_read(&tgt->free_sqes); if ((list_empty(&(cmd_mgr->free_list[index]))) || - (tgt->num_active_ios.counter >= max_sqes)) { + (tgt->num_active_ios.counter >= max_sqes) || + (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) { BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available " "ios(%d):sqes(%d)\n", tgt->num_active_ios.counter, tgt->max_sqes); @@ -463,6 +472,7 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) xid = io_req->xid; cmd_mgr->cmds[xid] = io_req; atomic_inc(&tgt->num_active_ios); + atomic_dec(&tgt->free_sqes); spin_unlock_bh(&cmd_mgr->free_list_lock[index]); INIT_LIST_HEAD(&io_req->link); @@ -481,14 +491,16 @@ struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) kref_init(&io_req->refcount); return io_req; } -static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) + +struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) { struct fcoe_port *port = tgt->port; - struct bnx2fc_hba *hba = port->priv; - struct bnx2fc_cmd_mgr *cmd_mgr = hba->cmd_mgr; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr; struct bnx2fc_cmd *io_req; struct list_head *listp; struct io_bdt *bd_tbl; + u32 free_sqes; u32 max_sqes; u16 xid; int index = get_cpu(); @@ -499,8 +511,10 @@ static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) * cmgr lock */ spin_lock_bh(&cmd_mgr->free_list_lock[index]); + free_sqes = atomic_read(&tgt->free_sqes); if ((list_empty(&cmd_mgr->free_list[index])) || - (tgt->num_active_ios.counter >= max_sqes)) { + (tgt->num_active_ios.counter >= max_sqes) || + (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) { spin_unlock_bh(&cmd_mgr->free_list_lock[index]); put_cpu(); return NULL; @@ -513,6 +527,7 @@ static struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) xid = io_req->xid; cmd_mgr->cmds[xid] = io_req; atomic_inc(&tgt->num_active_ios); + atomic_dec(&tgt->free_sqes); spin_unlock_bh(&cmd_mgr->free_list_lock[index]); put_cpu(); @@ -562,7 +577,8 @@ void bnx2fc_cmd_release(struct kref *ref) static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) { struct bnx2fc_mp_req *mp_req = &(io_req->mp_req); - struct bnx2fc_hba *hba = io_req->port->priv; + struct bnx2fc_interface *interface = io_req->port->priv; + struct bnx2fc_hba *hba = interface->hba; size_t sz = sizeof(struct fcoe_bd_ctx); /* clear tm flags */ @@ -580,13 +596,13 @@ static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) mp_req->mp_resp_bd = NULL; } if (mp_req->req_buf) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, mp_req->req_buf, mp_req->req_buf_dma); mp_req->req_buf = NULL; } if (mp_req->resp_buf) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, + dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, mp_req->resp_buf, mp_req->resp_buf_dma); mp_req->resp_buf = NULL; @@ -598,7 +614,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) struct bnx2fc_mp_req *mp_req; struct fcoe_bd_ctx *mp_req_bd; struct fcoe_bd_ctx *mp_resp_bd; - struct bnx2fc_hba *hba = io_req->port->priv; + struct bnx2fc_interface *interface = io_req->port->priv; + struct bnx2fc_hba *hba = interface->hba; dma_addr_t addr; size_t sz; @@ -607,7 +624,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) mp_req->req_len = sizeof(struct fcp_cmnd); io_req->data_xfer_len = mp_req->req_len; - mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, &mp_req->req_buf_dma, GFP_ATOMIC); if (!mp_req->req_buf) { @@ -616,7 +633,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) return FAILED; } - mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, + mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE, &mp_req->resp_buf_dma, GFP_ATOMIC); if (!mp_req->resp_buf) { @@ -624,8 +641,8 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) bnx2fc_free_mp_resc(io_req); return FAILED; } - memset(mp_req->req_buf, 0, PAGE_SIZE); - memset(mp_req->resp_buf, 0, PAGE_SIZE); + memset(mp_req->req_buf, 0, CNIC_PAGE_SIZE); + memset(mp_req->resp_buf, 0, CNIC_PAGE_SIZE); /* Allocate and map mp_req_bd and mp_resp_bd */ sz = sizeof(struct fcoe_bd_ctx); @@ -640,7 +657,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) mp_req->mp_resp_bd = dma_alloc_coherent(&hba->pcidev->dev, sz, &mp_req->mp_resp_bd_dma, GFP_ATOMIC); - if (!mp_req->mp_req_bd) { + if (!mp_req->mp_resp_bd) { printk(KERN_ERR PFX "unable to alloc MP resp bd\n"); bnx2fc_free_mp_resc(io_req); return FAILED; @@ -650,7 +667,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) mp_req_bd = mp_req->mp_req_bd; mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff; mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32); - mp_req_bd->buf_len = PAGE_SIZE; + mp_req_bd->buf_len = CNIC_PAGE_SIZE; mp_req_bd->flags = 0; /* @@ -662,7 +679,7 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) addr = mp_req->resp_buf_dma; mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff; mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32); - mp_resp_bd->buf_len = PAGE_SIZE; + mp_resp_bd->buf_len = CNIC_PAGE_SIZE; mp_resp_bd->flags = 0; return SUCCESS; @@ -671,10 +688,10 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) { struct fc_lport *lport; - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; + struct fc_rport *rport; + struct fc_rport_libfc_priv *rp; struct fcoe_port *port; - struct bnx2fc_hba *hba; + struct bnx2fc_interface *interface; struct bnx2fc_rport *tgt; struct bnx2fc_cmd *io_req; struct bnx2fc_mp_req *tm_req; @@ -690,14 +707,16 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) unsigned long start = jiffies; lport = shost_priv(host); + rport = starget_to_rport(scsi_target(sc_cmd->device)); port = lport_priv(lport); - hba = port->priv; + interface = port->priv; if (rport == NULL) { - printk(KERN_ALERT PFX "device_reset: rport is NULL\n"); + printk(KERN_ERR PFX "device_reset: rport is NULL\n"); rc = FAILED; goto tmf_err; } + rp = rport->dd_data; rc = fc_block_scsi_eh(sc_cmd); if (rc) @@ -737,7 +756,9 @@ retry_tmf: rc = bnx2fc_init_mp_req(io_req); if (rc == FAILED) { printk(KERN_ERR PFX "Task mgmt MP request init failed\n"); + spin_lock_bh(&tgt->tgt_lock); kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_unlock_bh(&tgt->tgt_lock); goto tmf_err; } @@ -766,7 +787,8 @@ retry_tmf: index = xid % BNX2FC_TASKS_PER_PAGE; /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx]; + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[task_idx]; task = &(task_page[index]); bnx2fc_init_mp_task(io_req, task); @@ -792,16 +814,30 @@ retry_tmf: spin_lock_bh(&tgt->tgt_lock); io_req->wait_for_comp = 0; - if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) + if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) { set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); + if (io_req->on_tmf_queue) { + list_del_init(&io_req->link); + io_req->on_tmf_queue = 0; + } + io_req->wait_for_comp = 1; + bnx2fc_initiate_cleanup(io_req); + spin_unlock_bh(&tgt->tgt_lock); + rc = wait_for_completion_timeout(&io_req->tm_done, + BNX2FC_FW_TIMEOUT); + spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_comp = 0; + if (!rc) + kref_put(&io_req->refcount, bnx2fc_cmd_release); + } spin_unlock_bh(&tgt->tgt_lock); if (!rc) { - printk(KERN_ERR PFX "task mgmt command failed...\n"); + BNX2FC_TGT_DBG(tgt, "task mgmt command failed...\n"); rc = FAILED; } else { - printk(KERN_ERR PFX "task mgmt command success...\n"); + BNX2FC_TGT_DBG(tgt, "task mgmt command success...\n"); rc = SUCCESS; } tmf_err: @@ -814,7 +850,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) struct bnx2fc_rport *tgt = io_req->tgt; struct fc_rport *rport = tgt->rport; struct fc_rport_priv *rdata = tgt->rdata; - struct bnx2fc_hba *hba; + struct bnx2fc_interface *interface; struct fcoe_port *port; struct bnx2fc_cmd *abts_io_req; struct fcoe_task_ctx_entry *task; @@ -831,7 +867,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_abts\n"); port = io_req->port; - hba = port->priv; + interface = port->priv; lport = port->lport; if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { @@ -841,7 +877,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) } if (rport == NULL) { - printk(KERN_ALERT PFX "initiate_abts: rport is NULL\n"); + printk(KERN_ERR PFX "initiate_abts: rport is NULL\n"); rc = FAILED; goto abts_err; } @@ -873,7 +909,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) /* Obtain oxid and rxid for the original exchange to be aborted */ fc_hdr->fh_ox_id = htons(io_req->xid); - fc_hdr->fh_rx_id = htons(io_req->task->rx_wr_tx_rd.rx_id); + fc_hdr->fh_rx_id = htons(io_req->task->rxwr_txrd.var_ctx.rx_id); sid = tgt->sid; did = rport->port_id; @@ -888,7 +924,8 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) index = xid % BNX2FC_TASKS_PER_PAGE; /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx]; + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[task_idx]; task = &(task_page[index]); bnx2fc_init_mp_task(abts_io_req, task); @@ -916,11 +953,81 @@ abts_err: return rc; } +int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, + enum fc_rctl r_ctl) +{ + struct fc_lport *lport; + struct bnx2fc_rport *tgt = orig_io_req->tgt; + struct bnx2fc_interface *interface; + struct fcoe_port *port; + struct bnx2fc_cmd *seq_clnp_req; + struct fcoe_task_ctx_entry *task; + struct fcoe_task_ctx_entry *task_page; + struct bnx2fc_els_cb_arg *cb_arg = NULL; + int task_idx, index; + u16 xid; + int rc = 0; + + BNX2FC_IO_DBG(orig_io_req, "bnx2fc_initiate_seq_cleanup xid = 0x%x\n", + orig_io_req->xid); + kref_get(&orig_io_req->refcount); + + port = orig_io_req->port; + interface = port->priv; + lport = port->lport; + + cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); + if (!cb_arg) { + printk(KERN_ERR PFX "Unable to alloc cb_arg for seq clnup\n"); + rc = -ENOMEM; + goto cleanup_err; + } + + seq_clnp_req = bnx2fc_elstm_alloc(tgt, BNX2FC_SEQ_CLEANUP); + if (!seq_clnp_req) { + printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n"); + rc = -ENOMEM; + kfree(cb_arg); + goto cleanup_err; + } + /* Initialize rest of io_req fields */ + seq_clnp_req->sc_cmd = NULL; + seq_clnp_req->port = port; + seq_clnp_req->tgt = tgt; + seq_clnp_req->data_xfer_len = 0; /* No data transfer for cleanup */ + + xid = seq_clnp_req->xid; + + task_idx = xid/BNX2FC_TASKS_PER_PAGE; + index = xid % BNX2FC_TASKS_PER_PAGE; + + /* Initialize task context for this IO request */ + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[task_idx]; + task = &(task_page[index]); + cb_arg->aborted_io_req = orig_io_req; + cb_arg->io_req = seq_clnp_req; + cb_arg->r_ctl = r_ctl; + cb_arg->offset = offset; + seq_clnp_req->cb_arg = cb_arg; + + printk(KERN_ERR PFX "call init_seq_cleanup_task\n"); + bnx2fc_init_seq_cleanup_task(seq_clnp_req, task, orig_io_req, offset); + + /* Obtain free SQ entry */ + bnx2fc_add_2_sq(tgt, xid); + + /* Ring doorbell */ + bnx2fc_ring_doorbell(tgt); +cleanup_err: + return rc; +} + int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) { struct fc_lport *lport; struct bnx2fc_rport *tgt = io_req->tgt; - struct bnx2fc_hba *hba; + struct bnx2fc_interface *interface; struct fcoe_port *port; struct bnx2fc_cmd *cleanup_io_req; struct fcoe_task_ctx_entry *task; @@ -933,7 +1040,7 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_cleanup\n"); port = io_req->port; - hba = port->priv; + interface = port->priv; lport = port->lport; cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP); @@ -955,7 +1062,8 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) index = xid % BNX2FC_TASKS_PER_PAGE; /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx]; + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[task_idx]; task = &(task_page[index]); orig_xid = io_req->xid; @@ -999,6 +1107,48 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); } +int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req) +{ + struct bnx2fc_rport *tgt = io_req->tgt; + struct fc_rport_priv *rdata = tgt->rdata; + int logo_issued; + int rc = SUCCESS; + int wait_cnt = 0; + + BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", + tgt->flags); + logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, + &tgt->flags); + io_req->wait_for_comp = 1; + bnx2fc_initiate_cleanup(io_req); + + spin_unlock_bh(&tgt->tgt_lock); + + wait_for_completion(&io_req->tm_done); + + io_req->wait_for_comp = 0; + /* + * release the reference taken in eh_abort to allow the + * target to re-login after flushing IOs + */ + kref_put(&io_req->refcount, bnx2fc_cmd_release); + + if (!logo_issued) { + clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); + mutex_lock(&lport->disc.disc_mutex); + lport->tt.rport_logoff(rdata); + mutex_unlock(&lport->disc.disc_mutex); + do { + msleep(BNX2FC_RELOGIN_WAIT_TIME); + if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) { + rc = FAILED; + break; + } + } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)); + } + spin_lock_bh(&tgt->tgt_lock); + return rc; +} /** * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding * SCSI command @@ -1023,7 +1173,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) lport = shost_priv(sc_cmd->device->host); if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) { - printk(KERN_ALERT PFX "eh_abort: link not ready\n"); + printk(KERN_ERR PFX "eh_abort: link not ready\n"); return rc; } @@ -1054,7 +1204,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) * io_req is no longer in the active_q. */ if (tgt->flush_in_prog) { - printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) " + printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " "flush in progress\n", io_req->xid); kref_put(&io_req->refcount, bnx2fc_cmd_release); spin_unlock_bh(&tgt->tgt_lock); @@ -1062,7 +1212,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) } if (io_req->on_active_queue == 0) { - printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) " + printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " "not on active_q\n", io_req->xid); /* * This condition can happen only due to the FW bug, @@ -1090,26 +1240,37 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) list_add_tail(&io_req->link, &tgt->io_retire_queue); init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { - /* Cancel the current timer running on this io_req */ + if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { + printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " + "already in abts processing\n", io_req->xid); if (cancel_delayed_work(&io_req->timeout_work)) kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ - set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); - rc = bnx2fc_initiate_abts(io_req); - } else { - printk(KERN_ALERT PFX "eh_abort: io_req (xid = 0x%x) " - "already in abts processing\n", io_req->xid); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return SUCCESS; + rc = bnx2fc_expl_logo(lport, io_req); + /* This only occurs when an task abort was requested while ABTS + is in progress. Setting the IO_CLEANUP flag will skip the + RRQ process in the case when the fw generated SCSI_CMD cmpl + was a result from the ABTS request rather than the CLEANUP + request */ + set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags); + goto out; } + + /* Cancel the current timer running on this io_req */ + if (cancel_delayed_work(&io_req->timeout_work)) + kref_put(&io_req->refcount, + bnx2fc_cmd_release); /* drop timer hold */ + set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); + io_req->wait_for_comp = 1; + rc = bnx2fc_initiate_abts(io_req); if (rc == FAILED) { - kref_put(&io_req->refcount, bnx2fc_cmd_release); + bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - return rc; + wait_for_completion(&io_req->tm_done); + spin_lock_bh(&tgt->tgt_lock); + io_req->wait_for_comp = 0; + goto done; } spin_unlock_bh(&tgt->tgt_lock); @@ -1117,12 +1278,16 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) spin_lock_bh(&tgt->tgt_lock); io_req->wait_for_comp = 0; - if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, - &io_req->req_flags))) { + if (test_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) { + BNX2FC_IO_DBG(io_req, "IO completed in a different context\n"); + rc = SUCCESS; + } else if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, + &io_req->req_flags))) { /* Let the scsi-ml try to recover this command */ printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", io_req->xid); - rc = FAILED; + rc = bnx2fc_expl_logo(lport, io_req); + goto out; } else { /* * We come here even when there was a race condition @@ -1134,13 +1299,49 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) bnx2fc_scsi_done(io_req, DID_ABORT); kref_put(&io_req->refcount, bnx2fc_cmd_release); } - +done: /* release the reference taken in eh_abort */ kref_put(&io_req->refcount, bnx2fc_cmd_release); +out: spin_unlock_bh(&tgt->tgt_lock); return rc; } +void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnp_req, + struct fcoe_task_ctx_entry *task, + u8 rx_state) +{ + struct bnx2fc_els_cb_arg *cb_arg = seq_clnp_req->cb_arg; + struct bnx2fc_cmd *orig_io_req = cb_arg->aborted_io_req; + u32 offset = cb_arg->offset; + enum fc_rctl r_ctl = cb_arg->r_ctl; + int rc = 0; + struct bnx2fc_rport *tgt = orig_io_req->tgt; + + BNX2FC_IO_DBG(orig_io_req, "Entered process_cleanup_compl xid = 0x%x" + "cmd_type = %d\n", + seq_clnp_req->xid, seq_clnp_req->cmd_type); + + if (rx_state == FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP) { + printk(KERN_ERR PFX "seq cleanup ignored - xid = 0x%x\n", + seq_clnp_req->xid); + goto free_cb_arg; + } + + spin_unlock_bh(&tgt->tgt_lock); + rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); + spin_lock_bh(&tgt->tgt_lock); + + if (rc) + printk(KERN_ERR PFX "clnup_compl: Unable to send SRR" + " IO will abort\n"); + seq_clnp_req->cb_arg = NULL; + kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); +free_cb_arg: + kfree(cb_arg); + return; +} + void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, struct fcoe_task_ctx_entry *task, u8 num_rq) @@ -1150,6 +1351,8 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, io_req->refcount.refcount.counter, io_req->cmd_type); bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); + if (io_req->wait_for_comp) + complete(&io_req->tm_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, @@ -1189,7 +1392,7 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, kref_put(&io_req->refcount, bnx2fc_cmd_release); /* drop timer hold */ - r_ctl = task->cmn.general.rsp_info.abts_rsp.r_ctl; + r_ctl = (u8)task->rxwr_only.union_ctx.comp_info.abts_rsp.r_ctl; switch (r_ctl) { case FC_RCTL_BA_ACC: @@ -1246,9 +1449,7 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) { struct scsi_cmnd *sc_cmd = io_req->sc_cmd; struct bnx2fc_rport *tgt = io_req->tgt; - struct list_head *list; - struct list_head *tmp; - struct bnx2fc_cmd *cmd; + struct bnx2fc_cmd *cmd, *tmp; int tm_lun = sc_cmd->device->lun; int rc = 0; int lun; @@ -1259,9 +1460,8 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) * Walk thru the active_ios queue and ABORT the IO * that matches with the LUN that was reset */ - list_for_each_safe(list, tmp, &tgt->active_cmd_queue) { + list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) { BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n"); - cmd = (struct bnx2fc_cmd *)list; lun = cmd->sc_cmd->device->lun; if (lun == tm_lun) { /* Initiate ABTS on this cmd */ @@ -1286,9 +1486,7 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req) { struct bnx2fc_rport *tgt = io_req->tgt; - struct list_head *list; - struct list_head *tmp; - struct bnx2fc_cmd *cmd; + struct bnx2fc_cmd *cmd, *tmp; int rc = 0; /* called with tgt_lock held */ @@ -1297,9 +1495,8 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req) * Walk thru the active_ios queue and ABORT the IO * that matches with the LUN that was reset */ - list_for_each_safe(list, tmp, &tgt->active_cmd_queue) { + list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) { BNX2FC_TGT_DBG(tgt, "TGT RST cmpl: scan for pending IOs\n"); - cmd = (struct bnx2fc_cmd *)list; /* Initiate ABTS */ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &cmd->req_flags)) { @@ -1344,12 +1541,13 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, fc_hdr = &(tm_req->resp_fc_hdr); hdr = (u64 *)fc_hdr; temp_hdr = (u64 *) - &task->cmn.general.cmd_info.mp_fc_frame.fc_hdr; + &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; hdr[0] = cpu_to_be64(temp_hdr[0]); hdr[1] = cpu_to_be64(temp_hdr[1]); hdr[2] = cpu_to_be64(temp_hdr[2]); - tm_req->resp_len = task->rx_wr_only.sgl_ctx.mul_sges.cur_sge_off; + tm_req->resp_len = + task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; rsp_buf = tm_req->resp_buf; @@ -1369,7 +1567,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, fc_hdr->fh_r_ctl); } if (!sc_cmd->SCp.ptr) { - printk(KERN_ALERT PFX "tm_compl: SCp.ptr is NULL\n"); + printk(KERN_ERR PFX "tm_compl: SCp.ptr is NULL\n"); return; } switch (io_req->fcp_status) { @@ -1401,7 +1599,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, io_req->on_tmf_queue = 0; } else { - printk(KERN_ALERT PFX "Command not on active_cmd_queue!\n"); + printk(KERN_ERR PFX "Command not on active_cmd_queue!\n"); return; } @@ -1442,6 +1640,8 @@ static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) { + struct bnx2fc_interface *interface = io_req->port->priv; + struct bnx2fc_hba *hba = interface->hba; struct scsi_cmnd *sc = io_req->sc_cmd; struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; struct scatterlist *sg; @@ -1453,7 +1653,8 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) u64 addr; int i; - sg_count = scsi_dma_map(sc); + sg_count = dma_map_sg(&hba->pcidev->dev, scsi_sglist(sc), + scsi_sg_count(sc), sc->sc_data_direction); scsi_for_each_sg(sc, sg, sg_count, i) { sg_len = sg_dma_len(sg); addr = sg_dma_address(sg); @@ -1478,20 +1679,24 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) return bd_count; } -static void bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) +static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) { struct scsi_cmnd *sc = io_req->sc_cmd; struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; int bd_count; - if (scsi_sg_count(sc)) + if (scsi_sg_count(sc)) { bd_count = bnx2fc_map_sg(io_req); - else { + if (bd_count == 0) + return -ENOMEM; + } else { bd_count = 0; bd[0].buf_addr_lo = bd[0].buf_addr_hi = 0; bd[0].buf_len = bd[0].flags = 0; } io_req->bd_tbl->bd_valid = bd_count; + + return 0; } static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req) @@ -1512,9 +1717,7 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(sc_cmd->device->lun, - (struct scsi_lun *) fcp_cmnd->fc_lun); - + int_to_scsilun(sc_cmd->device->lun, &fcp_cmnd->fc_lun); fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len); memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len); @@ -1588,7 +1791,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, if (rq_buff_len > num_rq * BNX2FC_RQ_BUF_SZ) { /* Invalid sense sense length. */ - printk(KERN_ALERT PFX "invalid sns length %d\n", + printk(KERN_ERR PFX "invalid sns length %d\n", rq_buff_len); /* reset rq_buff_len */ rq_buff_len = num_rq * BNX2FC_RQ_BUF_SZ; @@ -1618,7 +1821,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, fcp_sns_len = SCSI_SENSE_BUFFERSIZE; } - memset(sc_cmd->sense_buffer, 0, sizeof(sc_cmd->sense_buffer)); + memset(sc_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); if (fcp_sns_len) memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len); @@ -1663,12 +1866,6 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, tgt = (struct bnx2fc_rport *)&rp[1]; if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - if (test_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags)) { - sc_cmd->result = DID_NO_CONNECT << 16; - sc_cmd->scsi_done(sc_cmd); - return 0; - - } /* * Session is not offloaded yet. Let SCSI-ml retry * the command. @@ -1676,7 +1873,15 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, rc = SCSI_MLQUEUE_TARGET_BUSY; goto exit_qcmd; } - + if (tgt->retry_delay_timestamp) { + if (time_after(jiffies, tgt->retry_delay_timestamp)) { + tgt->retry_delay_timestamp = 0; + } else { + /* If retry_delay timer is active, flow off the ML */ + rc = SCSI_MLQUEUE_TARGET_BUSY; + goto exit_qcmd; + } + } io_req = bnx2fc_cmd_alloc(tgt); if (!io_req) { rc = SCSI_MLQUEUE_HOST_BUSY; @@ -1724,7 +1929,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* Fetch fcp_rsp from task context and perform cmd completion */ fcp_rsp = (struct fcoe_fcp_rsp_payload *) - &(task->cmn.general.rsp_info.fcp_rsp.payload); + &(task->rxwr_only.union_ctx.comp_info.fcp_rsp.payload); /* parse fcp_rsp and obtain sense data from RQ if available */ bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq); @@ -1734,7 +1939,6 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, printk(KERN_ERR PFX "SCp.ptr is NULL\n"); return; } - io_req->sc_cmd = NULL; if (io_req->on_active_queue) { list_del_init(&io_req->link); @@ -1754,6 +1958,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, } bnx2fc_unmap_sg_list(io_req); + io_req->sc_cmd = NULL; switch (io_req->fcp_status) { case FC_GOOD: @@ -1766,12 +1971,21 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, " fcp_resid = 0x%x\n", io_req->cdb_status, io_req->fcp_resid); sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; + + if (io_req->cdb_status == SAM_STAT_TASK_SET_FULL || + io_req->cdb_status == SAM_STAT_BUSY) { + /* Set the jiffies + retry_delay_timer * 100ms + for the rport/tgt */ + tgt->retry_delay_timestamp = jiffies + + fcp_rsp->retry_delay_timer * HZ / 10; + } + } if (io_req->fcp_resid) scsi_set_resid(sc_cmd, io_req->fcp_resid); break; default: - printk(KERN_ALERT PFX "scsi_cmd_compl: fcp_status = %d\n", + printk(KERN_ERR PFX "scsi_cmd_compl: fcp_status = %d\n", io_req->fcp_status); break; } @@ -1780,16 +1994,17 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, kref_put(&io_req->refcount, bnx2fc_cmd_release); } -static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, +int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_cmd *io_req) { struct fcoe_task_ctx_entry *task; struct fcoe_task_ctx_entry *task_page; struct scsi_cmnd *sc_cmd = io_req->sc_cmd; struct fcoe_port *port = tgt->port; - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_hba *hba = interface->hba; struct fc_lport *lport = port->lport; - struct fcoe_dev_stats *stats; + struct fc_stats *stats; int task_idx, index; u16 xid; @@ -1800,7 +2015,7 @@ static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, io_req->data_xfer_len = scsi_bufflen(sc_cmd); sc_cmd->SCp.ptr = (char *)io_req; - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); + stats = per_cpu_ptr(lport->stats, get_cpu()); if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { io_req->io_req_flags = BNX2FC_READ; stats->InputRequests++; @@ -1818,7 +2033,13 @@ static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, xid = io_req->xid; /* Build buffer descriptor list for firmware from sg list */ - bnx2fc_build_bd_list_from_sg(io_req); + if (bnx2fc_build_bd_list_from_sg(io_req)) { + printk(KERN_ERR PFX "BD list creation failed\n"); + spin_lock_bh(&tgt->tgt_lock); + kref_put(&io_req->refcount, bnx2fc_cmd_release); + spin_unlock_bh(&tgt->tgt_lock); + return -EAGAIN; + } task_idx = xid / BNX2FC_TASKS_PER_PAGE; index = xid % BNX2FC_TASKS_PER_PAGE; @@ -1845,7 +2066,8 @@ static int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, } /* Time IO req */ - bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT); + if (tgt->io_timeout) + bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT); /* Obtain free SQ entry */ bnx2fc_add_2_sq(tgt, xid); |
