diff options
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_io.c')
| -rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 335 |
1 files changed, 191 insertions, 144 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 350257c13a5b..33057908f147 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -24,7 +24,7 @@ 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, struct fcoe_fcp_rsp_payload *fcp_rsp, - u8 num_rq); + u8 num_rq, unsigned char *rq_data); void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req, unsigned int timer_msec) @@ -70,7 +70,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) &io_req->req_flags)) { /* Handle eh_abort timeout */ BNX2FC_IO_DBG(io_req, "eh_abort timed out\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { /* Handle internally generated ABTS timeout */ @@ -204,8 +204,8 @@ static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code) sc_cmd, host_byte(sc_cmd->result), sc_cmd->retries, sc_cmd->allowed); scsi_set_resid(sc_cmd, scsi_bufflen(sc_cmd)); - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); + bnx2fc_priv(sc_cmd)->io_req = NULL; + scsi_done(sc_cmd); } struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) @@ -240,6 +240,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) return NULL; } + cmgr->hba = hba; cmgr->free_list = kcalloc(arr_sz, sizeof(*cmgr->free_list), GFP_KERNEL); if (!cmgr->free_list) { @@ -256,7 +257,6 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) goto mem_err; } - cmgr->hba = hba; cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1); for (i = 0; i < arr_sz; i++) { @@ -295,7 +295,7 @@ struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba) /* Allocate pool of io_bdts - one for each bnx2fc_cmd */ mem_size = num_ios * sizeof(struct io_bdt *); - cmgr->io_bdt_pool = kmalloc(mem_size, GFP_KERNEL); + cmgr->io_bdt_pool = kzalloc(mem_size, GFP_KERNEL); if (!cmgr->io_bdt_pool) { printk(KERN_ERR PFX "failed to alloc io_bdt_pool\n"); goto mem_err; @@ -472,7 +472,7 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) u32 free_sqes; u32 max_sqes; u16 xid; - int index = get_cpu(); + int index = raw_smp_processor_id(); max_sqes = BNX2FC_SCSI_MAX_SQES; /* @@ -485,7 +485,6 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) (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; } @@ -498,7 +497,6 @@ struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) atomic_inc(&tgt->num_active_ios); atomic_dec(&tgt->free_sqes); spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - put_cpu(); INIT_LIST_HEAD(&io_req->link); @@ -658,10 +656,9 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) return SUCCESS; } -static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) +static int bnx2fc_initiate_tmf(struct fc_lport *lport, struct fc_rport *rport, + u64 tm_lun, u8 tm_flags) { - struct fc_lport *lport; - struct fc_rport *rport; struct fc_rport_libfc_priv *rp; struct fcoe_port *port; struct bnx2fc_interface *interface; @@ -670,7 +667,6 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) struct bnx2fc_mp_req *tm_req; struct fcoe_task_ctx_entry *task; struct fcoe_task_ctx_entry *task_page; - struct Scsi_Host *host = sc_cmd->device->host; struct fc_frame_header *fc_hdr; struct fcp_cmnd *fcp_cmnd; int task_idx, index; @@ -679,8 +675,6 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) u32 sid, did; unsigned long start = jiffies; - lport = shost_priv(host); - rport = starget_to_rport(scsi_target(sc_cmd->device)); port = lport_priv(lport); interface = port->priv; @@ -691,7 +685,7 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) } rp = rport->dd_data; - rc = fc_block_scsi_eh(sc_cmd); + rc = fc_block_rport(rport); if (rc) return rc; @@ -720,7 +714,7 @@ retry_tmf: goto retry_tmf; } /* Initialize rest of io_req fields */ - io_req->sc_cmd = sc_cmd; + io_req->sc_cmd = NULL; io_req->port = port; io_req->tgt = tgt; @@ -738,11 +732,13 @@ retry_tmf: /* Set TM flags */ io_req->io_req_flags = 0; tm_req->tm_flags = tm_flags; + tm_req->tm_lun = tm_lun; /* Fill FCP_CMND */ bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)tm_req->req_buf); fcp_cmnd = (struct fcp_cmnd *)tm_req->req_buf; - memset(fcp_cmnd->fc_cdb, 0, sc_cmd->cmd_len); + int_to_scsilun(tm_lun, &fcp_cmnd->fc_lun); + memset(fcp_cmnd->fc_cdb, 0, BNX2FC_MAX_CMD_LEN); fcp_cmnd->fc_dl = 0; /* Fill FC header */ @@ -765,8 +761,6 @@ retry_tmf: task = &(task_page[index]); bnx2fc_init_mp_task(io_req, task); - sc_cmd->SCp.ptr = (char *)io_req; - /* Obtain free SQ entry */ spin_lock_bh(&tgt->tgt_lock); bnx2fc_add_2_sq(tgt, xid); @@ -775,31 +769,32 @@ retry_tmf: io_req->on_tmf_queue = 1; list_add_tail(&io_req->link, &tgt->active_tm_queue); - init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; + init_completion(&io_req->abts_done); + io_req->wait_for_abts_comp = 1; /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->abts_done, interface->tm_timeout * HZ); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; 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; + io_req->wait_for_cleanup_comp = 1; + init_completion(&io_req->cleanup_done); bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - rc = wait_for_completion_timeout(&io_req->tm_done, + rc = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; if (!rc) kref_put(&io_req->refcount, bnx2fc_cmd_release); } @@ -863,7 +858,7 @@ int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) abts_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ABTS); if (!abts_io_req) { - printk(KERN_ERR PFX "abts: couldnt allocate cmd\n"); + printk(KERN_ERR PFX "abts: couldn't allocate cmd\n"); rc = FAILED; goto abts_err; } @@ -929,7 +924,6 @@ abts_err: 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; @@ -947,7 +941,6 @@ int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, 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) { @@ -958,7 +951,7 @@ int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, seq_clnp_req = bnx2fc_elstm_alloc(tgt, BNX2FC_SEQ_CLEANUP); if (!seq_clnp_req) { - printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n"); + printk(KERN_ERR PFX "cleanup: couldn't allocate cmd\n"); rc = -ENOMEM; kfree(cb_arg); goto cleanup_err; @@ -998,7 +991,6 @@ cleanup_err: int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) { - struct fc_lport *lport; struct bnx2fc_rport *tgt = io_req->tgt; struct bnx2fc_interface *interface; struct fcoe_port *port; @@ -1014,11 +1006,10 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) port = io_req->port; interface = port->priv; - lport = port->lport; cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP); if (!cleanup_io_req) { - printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n"); + printk(KERN_ERR PFX "cleanup: couldn't allocate cmd\n"); rc = -1; goto cleanup_err; } @@ -1047,6 +1038,9 @@ int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) /* Obtain free SQ entry */ bnx2fc_add_2_sq(tgt, xid); + /* Set flag that cleanup request is pending with the firmware */ + set_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + /* Ring doorbell */ bnx2fc_ring_doorbell(tgt); @@ -1064,7 +1058,10 @@ cleanup_err: */ int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd) { - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + struct fc_lport *lport = shost_priv(rport_to_shost(rport)); + + return bnx2fc_initiate_tmf(lport, rport, 0, FCP_TMF_TGT_RESET); } /** @@ -1077,16 +1074,21 @@ int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd) */ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) { - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); + struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); + struct fc_lport *lport = shost_priv(rport_to_shost(rport)); + + return bnx2fc_initiate_tmf(lport, rport, sc_cmd->device->lun, + FCP_TMF_LUN_RESET); } static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) + __must_hold(&tgt->tgt_lock) { struct bnx2fc_rport *tgt = io_req->tgt; - int rc = SUCCESS; unsigned int time_left; - io_req->wait_for_comp = 1; + init_completion(&io_req->cleanup_done); + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); @@ -1095,22 +1097,22 @@ static int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req) * Can't wait forever on cleanup response lest we let the SCSI error * handler wait forever */ - time_left = wait_for_completion_timeout(&io_req->tm_done, + time_left = wait_for_completion_timeout(&io_req->cleanup_done, BNX2FC_FW_TIMEOUT); - io_req->wait_for_comp = 0; - if (!time_left) + if (!time_left) { BNX2FC_IO_DBG(io_req, "%s(): Wait for cleanup timed out.\n", __func__); - /* - * Release reference held by SCSI command the cleanup completion - * hits the BNX2FC_CLEANUP case in bnx2fc_process_cq_compl() and - * thus the SCSI command is not returnedi by bnx2fc_scsi_done(). - */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); + /* + * Put the extra reference to the SCSI command since it would + * not have been returned in this case. + */ + kref_put(&io_req->refcount, bnx2fc_cmd_release); + } spin_lock_bh(&tgt->tgt_lock); - return rc; + io_req->wait_for_cleanup_comp = 0; + return SUCCESS; } /** @@ -1146,7 +1148,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) BNX2FC_TGT_DBG(tgt, "Entered bnx2fc_eh_abort\n"); spin_lock_bh(&tgt->tgt_lock); - io_req = (struct bnx2fc_cmd *)sc_cmd->SCp.ptr; + io_req = bnx2fc_priv(sc_cmd)->io_req; if (!io_req) { /* Command might have just completed */ printk(KERN_ERR PFX "eh_abort: io_req is NULL\n"); @@ -1198,7 +1200,8 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Move IO req to retire queue */ list_add_tail(&io_req->link, &tgt->io_retire_queue); - init_completion(&io_req->tm_done); + init_completion(&io_req->abts_done); + init_completion(&io_req->cleanup_done); if (test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " @@ -1211,13 +1214,14 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) * cleanup the command and return that I/O was successfully * aborted. */ - rc = bnx2fc_abts_cleanup(io_req); + bnx2fc_abts_cleanup(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); + rc = FAILED; goto done; } @@ -1226,26 +1230,28 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) 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; + io_req->wait_for_abts_comp = 1; rc = bnx2fc_initiate_abts(io_req); if (rc == FAILED) { + io_req->wait_for_cleanup_comp = 1; bnx2fc_initiate_cleanup(io_req); spin_unlock_bh(&tgt->tgt_lock); - wait_for_completion(&io_req->tm_done); + wait_for_completion(&io_req->cleanup_done); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_cleanup_comp = 0; goto done; } spin_unlock_bh(&tgt->tgt_lock); /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */ - time_left = wait_for_completion_timeout(&io_req->tm_done, - (2 * rp->r_a_tov + 1) * HZ); + time_left = wait_for_completion_timeout(&io_req->abts_done, + msecs_to_jiffies(2 * rp->r_a_tov + 1)); if (time_left) - BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for tm_done"); + BNX2FC_IO_DBG(io_req, + "Timed out in eh_abort waiting for abts_done"); spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; + io_req->wait_for_abts_comp = 0; 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; @@ -1320,10 +1326,29 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl " "refcnt = %d, cmd_type = %d\n", kref_read(&io_req->refcount), io_req->cmd_type); + /* + * Test whether there is a cleanup request pending. If not just + * exit. + */ + if (!test_and_clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, + &io_req->req_flags)) + return; + /* + * If we receive a cleanup completion for this request then the + * firmware will not give us an abort completion for this request + * so clear any ABTS pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags) && + !test_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { + set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags); + if (io_req->wait_for_abts_comp) + complete(&io_req->abts_done); + } + 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); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); } void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, @@ -1347,6 +1372,16 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, return; } + /* + * If we receive an ABTS completion here then we will not receive + * a cleanup completion so clear any cleanup pending flags. + */ + if (test_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags)) { + clear_bit(BNX2FC_FLAG_ISSUE_CLEANUP_REQ, &io_req->req_flags); + if (io_req->wait_for_cleanup_comp) + complete(&io_req->cleanup_done); + } + /* Do not issue RRQ as this IO is already cleanedup */ if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags)) @@ -1391,10 +1426,10 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, bnx2fc_cmd_timer_set(io_req, r_a_tov); io_compl: - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } else { /* * We end up here when ABTS is issued as @@ -1418,10 +1453,9 @@ io_compl: 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 bnx2fc_cmd *cmd, *tmp; - u64 tm_lun = sc_cmd->device->lun; + struct bnx2fc_mp_req *tm_req = &io_req->mp_req; u64 lun; int rc = 0; @@ -1433,8 +1467,10 @@ static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) */ list_for_each_entry_safe(cmd, tmp, &tgt->active_cmd_queue, link) { BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n"); + if (!cmd->sc_cmd) + continue; lun = cmd->sc_cmd->device->lun; - if (lun == tm_lun) { + if (lun == tm_req->tm_lun) { /* Initiate ABTS on this cmd */ if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &cmd->req_flags)) { @@ -1486,7 +1522,8 @@ static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req) } void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, u8 num_rq) + struct fcoe_task_ctx_entry *task, u8 num_rq, + unsigned char *rq_data) { struct bnx2fc_mp_req *tm_req; struct fc_frame_header *fc_hdr; @@ -1525,7 +1562,7 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, if (fc_hdr->fh_r_ctl == FC_RCTL_DD_CMD_STATUS) { bnx2fc_parse_fcp_rsp(io_req, (struct fcoe_fcp_rsp_payload *) - rsp_buf, num_rq); + rsp_buf, num_rq, rq_data); if (io_req->fcp_rsp_code == 0) { /* TM successful */ if (tm_req->tm_flags & FCP_TMF_LUN_RESET) @@ -1537,31 +1574,36 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, printk(KERN_ERR PFX "tmf's fc_hdr r_ctl = 0x%x\n", fc_hdr->fh_r_ctl); } - if (!sc_cmd->SCp.ptr) { - printk(KERN_ERR PFX "tm_compl: SCp.ptr is NULL\n"); - return; - } - switch (io_req->fcp_status) { - case FC_GOOD: - if (io_req->cdb_status == 0) { - /* Good IO completion */ - sc_cmd->result = DID_OK << 16; - } else { - /* Transport status is good, SCSI status not good */ - sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; + if (sc_cmd) { + if (!bnx2fc_priv(sc_cmd)->io_req) { + printk(KERN_ERR PFX "tm_compl: io_req is NULL\n"); + return; + } + switch (io_req->fcp_status) { + case FC_GOOD: + if (io_req->cdb_status == 0) { + /* Good IO completion */ + sc_cmd->result = DID_OK << 16; + } else { + /* Transport status is good, SCSI status not good */ + sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; + } + if (io_req->fcp_resid) + scsi_set_resid(sc_cmd, io_req->fcp_resid); + break; + + default: + BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n", + io_req->fcp_status); + break; } - if (io_req->fcp_resid) - scsi_set_resid(sc_cmd, io_req->fcp_resid); - break; - default: - BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n", - io_req->fcp_status); - break; - } + sc_cmd = io_req->sc_cmd; + io_req->sc_cmd = NULL; - sc_cmd = io_req->sc_cmd; - io_req->sc_cmd = NULL; + bnx2fc_priv(sc_cmd)->io_req = NULL; + scsi_done(sc_cmd); + } /* check if the io_req exists in tgt's tmf_q */ if (io_req->on_tmf_queue) { @@ -1574,13 +1616,10 @@ void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, return; } - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) { + if (io_req->wait_for_abts_comp) { BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n"); - complete(&io_req->tm_done); + complete(&io_req->abts_done); } } @@ -1624,6 +1663,7 @@ static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) u64 addr; int i; + WARN_ON(scsi_sg_count(sc) > BNX2FC_MAX_BDS_PER_CMD); /* * Use dma_map_sg directly to ensure we're using the correct * dev struct off of pcidev. @@ -1671,6 +1711,16 @@ static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) } io_req->bd_tbl->bd_valid = bd_count; + /* + * Return the command to ML if BD count exceeds the max number + * that can be handled by FW. + */ + if (bd_count > BNX2FC_FW_MAX_BDS_PER_CMD) { + pr_err("bd_count = %d exceeded FW supported max BD(255), task_id = 0x%x\n", + bd_count, io_req->xid); + return -ENOMEM; + } + return 0; } @@ -1694,15 +1744,9 @@ static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req) void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, struct fcp_cmnd *fcp_cmnd) { - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - 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); - fcp_cmnd->fc_cmdref = 0; fcp_cmnd->fc_pri_ta = 0; fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags; @@ -1712,15 +1756,11 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, struct fcoe_fcp_rsp_payload *fcp_rsp, - u8 num_rq) + u8 num_rq, unsigned char *rq_data) { struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - struct bnx2fc_rport *tgt = io_req->tgt; u8 rsp_flags = fcp_rsp->fcp_flags.flags; u32 rq_buff_len = 0; - int i; - unsigned char *rq_data; - unsigned char *dummy; int fcp_sns_len = 0; int fcp_rsp_len = 0; @@ -1731,8 +1771,7 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, io_req->fcp_resid = fcp_rsp->fcp_resid; io_req->scsi_comp_flags = rsp_flags; - CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status = - fcp_rsp->scsi_status_code; + io_req->cdb_status = fcp_rsp->scsi_status_code; /* Fetch fcp_rsp_info and fcp_sns_info if available */ if (num_rq) { @@ -1766,14 +1805,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, rq_buff_len = num_rq * BNX2FC_RQ_BUF_SZ; } - rq_data = bnx2fc_get_next_rqe(tgt, 1); - - if (num_rq > 1) { - /* We do not need extra sense data */ - for (i = 1; i < num_rq; i++) - dummy = bnx2fc_get_next_rqe(tgt, 1); - } - /* fetch fcp_rsp_code */ if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) { /* Only for task management function */ @@ -1794,9 +1825,6 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, if (fcp_sns_len) memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len); - /* return RQ entries */ - for (i = 0; i < num_rq; i++) - bnx2fc_return_rqe(tgt, 1); } } @@ -1822,7 +1850,7 @@ int bnx2fc_queuecommand(struct Scsi_Host *host, rval = fc_remote_port_chkready(rport); if (rval) { sc_cmd->result = rval; - sc_cmd->scsi_done(sc_cmd); + scsi_done(sc_cmd); return 0; } @@ -1875,13 +1903,12 @@ exit_qcmd: void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, struct fcoe_task_ctx_entry *task, - u8 num_rq) + u8 num_rq, unsigned char *rq_data) { struct fcoe_fcp_rsp_payload *fcp_rsp; struct bnx2fc_rport *tgt = io_req->tgt; struct scsi_cmnd *sc_cmd; - struct Scsi_Host *host; - + u16 scope = 0, qualifier = 0; /* scsi_cmd_cmpl is called with tgt lock held */ @@ -1889,6 +1916,12 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, /* we will not receive ABTS response for this IO */ BNX2FC_IO_DBG(io_req, "Timer context finished processing " "this scsi cmd\n"); + if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, + &io_req->req_flags)) { + BNX2FC_IO_DBG(io_req, + "Actual completion after cleanup request cleaning up\n"); + bnx2fc_process_cleanup_compl(io_req, task, num_rq); + } return; } @@ -1908,11 +1941,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, &(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); + bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq, rq_data); - host = sc_cmd->device->host; - if (!sc_cmd->SCp.ptr) { - printk(KERN_ERR PFX "SCp.ptr is NULL\n"); + if (!bnx2fc_priv(sc_cmd)->io_req) { + printk(KERN_ERR PFX "io_req is NULL\n"); return; } @@ -1927,10 +1959,10 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, * between command abort and (late) completion. */ BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n"); - if (io_req->wait_for_comp) + if (io_req->wait_for_abts_comp) if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags)) - complete(&io_req->tm_done); + complete(&io_req->abts_done); } bnx2fc_unmap_sg_list(io_req); @@ -1950,12 +1982,30 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, 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; + /* Newer array firmware with BUSY or + * TASK_SET_FULL may return a status that needs + * the scope bits masked. + * Or a huge delay timestamp up to 27 minutes + * can result. + */ + if (fcp_rsp->retry_delay_timer) { + /* Upper 2 bits */ + scope = fcp_rsp->retry_delay_timer + & 0xC000; + /* Lower 14 bits */ + qualifier = fcp_rsp->retry_delay_timer + & 0x3FFF; + } + if (scope > 0 && qualifier > 0 && + qualifier <= 0x3FEF) { + /* Set the jiffies + + * retry_delay_timer * 100ms + * for the rport/tgt + */ + tgt->retry_delay_timestamp = jiffies + + (qualifier * HZ / 10); + } } - } if (io_req->fcp_resid) scsi_set_resid(sc_cmd, io_req->fcp_resid); @@ -1965,8 +2015,8 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, io_req->fcp_status); break; } - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); + bnx2fc_priv(sc_cmd)->io_req = NULL; + scsi_done(sc_cmd); kref_put(&io_req->refcount, bnx2fc_cmd_release); } @@ -1980,7 +2030,6 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_interface *interface = port->priv; struct bnx2fc_hba *hba = interface->hba; struct fc_lport *lport = port->lport; - struct fc_stats *stats; int task_idx, index; u16 xid; @@ -1991,22 +2040,20 @@ int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, io_req->port = port; io_req->tgt = tgt; io_req->data_xfer_len = scsi_bufflen(sc_cmd); - sc_cmd->SCp.ptr = (char *)io_req; + bnx2fc_priv(sc_cmd)->io_req = io_req; - 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++; - stats->InputBytes += io_req->data_xfer_len; + this_cpu_inc(lport->stats->InputRequests); + this_cpu_add(lport->stats->InputBytes, io_req->data_xfer_len); } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { io_req->io_req_flags = BNX2FC_WRITE; - stats->OutputRequests++; - stats->OutputBytes += io_req->data_xfer_len; + this_cpu_inc(lport->stats->OutputRequests); + this_cpu_add(lport->stats->OutputBytes, io_req->data_xfer_len); } else { io_req->io_req_flags = 0; - stats->ControlRequests++; + this_cpu_inc(lport->stats->ControlRequests); } - put_cpu(); xid = io_req->xid; |
