Merge branch 'imx/imx6q' into next/soc
[pandora-kernel.git] / drivers / scsi / bnx2fc / bnx2fc_io.c
index 45eba6d..6cc3789 100644 (file)
@@ -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);