diff options
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_io.c')
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_io.c | 194 |
1 files changed, 157 insertions, 37 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 45eba6d609c..6cc3789075b 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 - 2011 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 @@ -18,8 +18,6 @@ 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 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) { @@ -419,8 +423,8 @@ 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; @@ -485,11 +489,12 @@ 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; @@ -570,7 +575,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 */ @@ -606,7 +612,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; @@ -682,7 +689,7 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); struct fc_rport_libfc_priv *rp = rport->dd_data; 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; @@ -699,10 +706,10 @@ static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) lport = shost_priv(host); 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; } @@ -745,7 +752,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; } @@ -774,7 +783,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); @@ -806,10 +816,10 @@ retry_tmf: 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: @@ -822,7 +832,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; @@ -839,7 +849,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)) { @@ -849,7 +859,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; } @@ -896,7 +906,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); @@ -924,11 +935,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; @@ -941,7 +1022,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); @@ -963,7 +1044,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; @@ -1031,7 +1113,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; } @@ -1062,7 +1144,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); @@ -1070,7 +1152,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, @@ -1108,7 +1190,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) 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) " + printk(KERN_ERR 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); @@ -1149,6 +1231,42 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) 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; + } + kref_get(&orig_io_req->refcount); + + 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) @@ -1378,7 +1496,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) { @@ -1410,7 +1528,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; } @@ -1597,7 +1715,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; @@ -1780,7 +1898,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, 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; } @@ -1789,14 +1907,15 @@ 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; int task_idx, index; @@ -1854,7 +1973,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); |