diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-30 22:36:02 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-30 22:36:02 +0400 |
commit | 6c6e3b828b2a13b923b9465fc4316c5bdc92291f (patch) | |
tree | ca027f7d7645c577ed76fcc8358163eb1689d8ae /drivers/scsi/bnx2fc/bnx2fc_hwi.c | |
parent | c11abbbaa3252875c5740a6880b9a1a6f1e2a870 (diff) | |
parent | d272281c390eb6c3f1e70ed0337c9e619d99cd9c (diff) | |
download | linux-6c6e3b828b2a13b923b9465fc4316c5bdc92291f.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (71 commits)
[SCSI] fcoe: cleanup cpu selection for incoming requests
[SCSI] fcoe: add fip retry to avoid missing critical keep alive
[SCSI] libfc: fix warn on in lport retry
[SCSI] libfc: Remove the reference to FCP packet from scsi_cmnd in case of error
[SCSI] libfc: cleanup sending SRR request
[SCSI] libfc: two minor changes in comments
[SCSI] libfc, fcoe: ignore rx frame with wrong xid info
[SCSI] libfc: release exchg cache
[SCSI] libfc: use FC_MAX_ERROR_CNT
[SCSI] fcoe: remove unused ptype field in fcoe_rcv_info
[SCSI] bnx2fc: Update copyright and bump version to 1.0.4
[SCSI] bnx2fc: Tx BDs cache in write tasks
[SCSI] bnx2fc: Do not arm CQ when there are no CQEs
[SCSI] bnx2fc: hold tgt lock when calling cmd_release
[SCSI] bnx2fc: Enable support for sequence level error recovery
[SCSI] bnx2fc: HSI changes for tape
[SCSI] bnx2fc: Handle REC_TOV error code from firmware
[SCSI] bnx2fc: REC/SRR link service request and response handling
[SCSI] bnx2fc: Support 'sequence cleanup' task
[SCSI] dh_rdac: Associate HBA and storage in rdac_controller to support partitions in storage
...
Diffstat (limited to 'drivers/scsi/bnx2fc/bnx2fc_hwi.c')
-rw-r--r-- | drivers/scsi/bnx2fc/bnx2fc_hwi.c | 433 |
1 files changed, 338 insertions, 95 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c index 09bdd9b88d1a..72cfb14acd3a 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c @@ -2,7 +2,7 @@ * This file contains the code that low level functions that interact * with 57712 FCoE firmware. * - * 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 @@ -23,7 +23,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, struct fcoe_kcqe *ofld_kcqe); static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code); static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *conn_destroy); + struct fcoe_kcqe *destroy_kcqe); int bnx2fc_send_stat_req(struct bnx2fc_hba *hba) { @@ -67,7 +67,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) int rc = 0; if (!hba->cnic) { - printk(KERN_ALERT PFX "hba->cnic NULL during fcoe fw init\n"); + printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n"); return -ENODEV; } @@ -103,6 +103,7 @@ int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION; fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION; + fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma; fcoe_init2.hash_tbl_pbl_addr_hi = (u32) ((u64) hba->hash_tbl_pbl_dma >> 32); @@ -165,7 +166,8 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, struct bnx2fc_rport *tgt) { struct fc_lport *lport = port->lport; - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_hba *hba = interface->hba; struct kwqe *kwqe_arr[4]; struct fcoe_kwqe_conn_offload1 ofld_req1; struct fcoe_kwqe_conn_offload2 ofld_req2; @@ -227,7 +229,7 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, ofld_req3.hdr.flags = (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - ofld_req3.vlan_tag = hba->vlan_id << + ofld_req3.vlan_tag = interface->vlan_id << FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT; ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT; @@ -277,8 +279,20 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) << FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT); + /* + * Info from PRLI response, this info is used for sequence level error + * recovery support + */ + if (tgt->dev_type == TYPE_TAPE) { + ofld_req3.flags |= 1 << + FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT; + ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED) + ? 1 : 0) << + FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT); + } + /* vlan flag */ - ofld_req3.flags |= (hba->vlan_enabled << + ofld_req3.flags |= (interface->vlan_enabled << FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT); /* C2_VALID and ACK flags are not set as they are not suppported */ @@ -300,12 +314,13 @@ int bnx2fc_send_session_ofld_req(struct fcoe_port *port, ofld_req4.src_mac_addr_mid[1] = port->data_src_addr[2]; ofld_req4.src_mac_addr_hi[0] = port->data_src_addr[1]; ofld_req4.src_mac_addr_hi[1] = port->data_src_addr[0]; - ofld_req4.dst_mac_addr_lo[0] = hba->ctlr.dest_addr[5];/* fcf mac */ - ofld_req4.dst_mac_addr_lo[1] = hba->ctlr.dest_addr[4]; - ofld_req4.dst_mac_addr_mid[0] = hba->ctlr.dest_addr[3]; - ofld_req4.dst_mac_addr_mid[1] = hba->ctlr.dest_addr[2]; - ofld_req4.dst_mac_addr_hi[0] = hba->ctlr.dest_addr[1]; - ofld_req4.dst_mac_addr_hi[1] = hba->ctlr.dest_addr[0]; + ofld_req4.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; + /* fcf mac */ + ofld_req4.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + ofld_req4.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + ofld_req4.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + ofld_req4.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + ofld_req4.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma; ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32); @@ -335,7 +350,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, struct bnx2fc_rport *tgt) { struct kwqe *kwqe_arr[2]; - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_hba *hba = interface->hba; struct fcoe_kwqe_conn_enable_disable enbl_req; struct fc_lport *lport = port->lport; struct fc_rport *rport = tgt->rport; @@ -358,12 +374,12 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, enbl_req.src_mac_addr_hi[1] = port->data_src_addr[0]; memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN); - enbl_req.dst_mac_addr_lo[0] = hba->ctlr.dest_addr[5];/* fcf mac */ - enbl_req.dst_mac_addr_lo[1] = hba->ctlr.dest_addr[4]; - enbl_req.dst_mac_addr_mid[0] = hba->ctlr.dest_addr[3]; - enbl_req.dst_mac_addr_mid[1] = hba->ctlr.dest_addr[2]; - enbl_req.dst_mac_addr_hi[0] = hba->ctlr.dest_addr[1]; - enbl_req.dst_mac_addr_hi[1] = hba->ctlr.dest_addr[0]; + enbl_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; + enbl_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + enbl_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + enbl_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + enbl_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + enbl_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; port_id = fc_host_port_id(lport->host); if (port_id != tgt->sid) { @@ -379,10 +395,10 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, enbl_req.d_id[0] = (port_id & 0x000000FF); enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8; enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16; - enbl_req.vlan_tag = hba->vlan_id << + enbl_req.vlan_tag = interface->vlan_id << FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; - enbl_req.vlan_flag = hba->vlan_enabled; + enbl_req.vlan_flag = interface->vlan_enabled; enbl_req.context_id = tgt->context_id; enbl_req.conn_id = tgt->fcoe_conn_id; @@ -402,7 +418,8 @@ static int bnx2fc_send_session_enable_req(struct fcoe_port *port, int bnx2fc_send_session_disable_req(struct fcoe_port *port, struct bnx2fc_rport *tgt) { - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_hba *hba = interface->hba; struct fcoe_kwqe_conn_enable_disable disable_req; struct kwqe *kwqe_arr[2]; struct fc_rport *rport = tgt->rport; @@ -423,12 +440,12 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port, disable_req.src_mac_addr_hi[0] = tgt->src_addr[1]; disable_req.src_mac_addr_hi[1] = tgt->src_addr[0]; - disable_req.dst_mac_addr_lo[0] = hba->ctlr.dest_addr[5];/* fcf mac */ - disable_req.dst_mac_addr_lo[1] = hba->ctlr.dest_addr[4]; - disable_req.dst_mac_addr_mid[0] = hba->ctlr.dest_addr[3]; - disable_req.dst_mac_addr_mid[1] = hba->ctlr.dest_addr[2]; - disable_req.dst_mac_addr_hi[0] = hba->ctlr.dest_addr[1]; - disable_req.dst_mac_addr_hi[1] = hba->ctlr.dest_addr[0]; + disable_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; + disable_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; + disable_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; + disable_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; + disable_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; + disable_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; port_id = tgt->sid; disable_req.s_id[0] = (port_id & 0x000000FF); @@ -442,11 +459,11 @@ int bnx2fc_send_session_disable_req(struct fcoe_port *port, disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16; disable_req.context_id = tgt->context_id; disable_req.conn_id = tgt->fcoe_conn_id; - disable_req.vlan_tag = hba->vlan_id << + disable_req.vlan_tag = interface->vlan_id << FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; disable_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; - disable_req.vlan_flag = hba->vlan_enabled; + disable_req.vlan_flag = interface->vlan_enabled; kwqe_arr[0] = (struct kwqe *) &disable_req; @@ -525,7 +542,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, { struct fcoe_port *port = tgt->port; struct fc_lport *lport = port->lport; - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; struct bnx2fc_unsol_els *unsol_els; struct fc_frame_header *fh; struct fc_frame *fp; @@ -586,7 +603,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, fr_eof(fp) = FC_EOF_T; fr_crc(fp) = cpu_to_le32(~crc); unsol_els->lport = lport; - unsol_els->hba = hba; + unsol_els->hba = interface->hba; unsol_els->fp = fp; INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); @@ -608,9 +625,12 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) u32 frame_len, len; struct bnx2fc_cmd *io_req = NULL; struct fcoe_task_ctx_entry *task, *task_page; - struct bnx2fc_hba *hba = tgt->port->priv; + struct bnx2fc_interface *interface = tgt->port->priv; + struct bnx2fc_hba *hba = interface->hba; int task_idx, index; int rc = 0; + u64 err_warn_bit_map; + u8 err_warn = 0xff; BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe); @@ -673,39 +693,43 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n", err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); - bnx2fc_return_rqe(tgt, 1); if (xid > BNX2FC_MAX_XID) { BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid); - spin_unlock_bh(&tgt->tgt_lock); - break; + goto ret_err_rqe; } task_idx = xid / BNX2FC_TASKS_PER_PAGE; index = xid % BNX2FC_TASKS_PER_PAGE; task_page = (struct fcoe_task_ctx_entry *) - hba->task_ctx[task_idx]; + hba->task_ctx[task_idx]; task = &(task_page[index]); io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; - if (!io_req) { - spin_unlock_bh(&tgt->tgt_lock); - break; - } + if (!io_req) + goto ret_err_rqe; if (io_req->cmd_type != BNX2FC_SCSI_CMD) { printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); - spin_unlock_bh(&tgt->tgt_lock); - break; + goto ret_err_rqe; } if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags)) { BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in " "progress.. ignore unsol err\n"); - spin_unlock_bh(&tgt->tgt_lock); - break; + goto ret_err_rqe; + } + + err_warn_bit_map = (u64) + ((u64)err_entry->data.err_warn_bitmap_hi << 32) | + (u64)err_entry->data.err_warn_bitmap_lo; + for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { + if (err_warn_bit_map & (u64)((u64)1 << i)) { + err_warn = i; + break; + } } /* @@ -715,26 +739,61 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) * logging out the target, when the ABTS eventually * times out. */ - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, - &io_req->req_flags)) { - /* - * Cancel the timeout_work, as we received IO - * completion with FW error. - */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* timer hold */ - - rc = bnx2fc_initiate_abts(io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(io_req, "err_warn: initiate_abts " - "failed. issue cleanup\n"); - rc = bnx2fc_initiate_cleanup(io_req); - BUG_ON(rc); - } - } else + if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { printk(KERN_ERR PFX "err_warn: io_req (0x%x) already " "in ABTS processing\n", xid); + goto ret_err_rqe; + } + BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn); + if (tgt->dev_type != TYPE_TAPE) + goto skip_rec; + switch (err_warn) { + case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION: + case FCOE_ERROR_CODE_DATA_OOO_RO: + case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT: + case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET: + case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ: + case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET: + BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n", + xid); + memset(&io_req->err_entry, 0, + sizeof(struct fcoe_err_report_entry)); + memcpy(&io_req->err_entry, err_entry, + sizeof(struct fcoe_err_report_entry)); + if (!test_bit(BNX2FC_FLAG_SRR_SENT, + &io_req->req_flags)) { + spin_unlock_bh(&tgt->tgt_lock); + rc = bnx2fc_send_rec(io_req); + spin_lock_bh(&tgt->tgt_lock); + + if (rc) + goto skip_rec; + } else + printk(KERN_ERR PFX "SRR in progress\n"); + goto ret_err_rqe; + break; + default: + break; + } + +skip_rec: + set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags); + /* + * Cancel the timeout_work, as we received IO + * completion with FW error. + */ + if (cancel_delayed_work(&io_req->timeout_work)) + kref_put(&io_req->refcount, bnx2fc_cmd_release); + + rc = bnx2fc_initiate_abts(io_req); + if (rc != SUCCESS) { + printk(KERN_ERR PFX "err_warn: initiate_abts " + "failed xid = 0x%x. issue cleanup\n", + io_req->xid); + bnx2fc_initiate_cleanup(io_req); + } +ret_err_rqe: + bnx2fc_return_rqe(tgt, 1); spin_unlock_bh(&tgt->tgt_lock); break; @@ -755,6 +814,47 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x", err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); + if (xid > BNX2FC_MAX_XID) { + BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid); + goto ret_warn_rqe; + } + + err_warn_bit_map = (u64) + ((u64)err_entry->data.err_warn_bitmap_hi << 32) | + (u64)err_entry->data.err_warn_bitmap_lo; + for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { + if (err_warn_bit_map & (u64) (1 << i)) { + err_warn = i; + break; + } + } + BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn); + + task_idx = xid / BNX2FC_TASKS_PER_PAGE; + index = xid % BNX2FC_TASKS_PER_PAGE; + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[task_idx]; + task = &(task_page[index]); + io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; + if (!io_req) + goto ret_warn_rqe; + + if (io_req->cmd_type != BNX2FC_SCSI_CMD) { + printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); + goto ret_warn_rqe; + } + + memset(&io_req->err_entry, 0, + sizeof(struct fcoe_err_report_entry)); + memcpy(&io_req->err_entry, err_entry, + sizeof(struct fcoe_err_report_entry)); + + if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION) + /* REC_TOV is not a warning code */ + BUG_ON(1); + else + BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n"); +ret_warn_rqe: bnx2fc_return_rqe(tgt, 1); spin_unlock_bh(&tgt->tgt_lock); break; @@ -770,7 +870,8 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe) struct fcoe_task_ctx_entry *task; struct fcoe_task_ctx_entry *task_page; 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 bnx2fc_cmd *io_req; int task_idx, index; u16 xid; @@ -781,7 +882,7 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe) spin_lock_bh(&tgt->tgt_lock); xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; if (xid >= BNX2FC_MAX_TASKS) { - printk(KERN_ALERT PFX "ERROR:xid out of range\n"); + printk(KERN_ERR PFX "ERROR:xid out of range\n"); spin_unlock_bh(&tgt->tgt_lock); return; } @@ -861,6 +962,13 @@ void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe) kref_put(&io_req->refcount, bnx2fc_cmd_release); break; + case BNX2FC_SEQ_CLEANUP: + BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n", + io_req->xid); + bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state); + kref_put(&io_req->refcount, bnx2fc_cmd_release); + break; + default: printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type); break; @@ -962,8 +1070,10 @@ unlock: 1 - tgt->cq_curr_toggle_bit; } } - bnx2fc_arm_cq(tgt); - atomic_add(num_free_sqes, &tgt->free_sqes); + if (num_free_sqes) { + bnx2fc_arm_cq(tgt); + atomic_add(num_free_sqes, &tgt->free_sqes); + } spin_unlock_bh(&tgt->cq_lock); return 0; } @@ -983,7 +1093,7 @@ static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id]; if (!tgt) { - printk(KERN_ALERT PFX "conn_id 0x%x not valid\n", conn_id); + printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id); return; } @@ -1004,6 +1114,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, { struct bnx2fc_rport *tgt; struct fcoe_port *port; + struct bnx2fc_interface *interface; u32 conn_id; u32 context_id; int rc; @@ -1018,8 +1129,9 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n", ofld_kcqe->fcoe_conn_context_id); port = tgt->port; - if (hba != tgt->port->priv) { - printk(KERN_ALERT PFX "ERROR:ofld_cmpl: HBA mis-match\n"); + interface = tgt->port->priv; + if (hba != interface->hba) { + printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n"); goto ofld_cmpl_err; } /* @@ -1040,7 +1152,7 @@ static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, /* now enable the session */ rc = bnx2fc_send_session_enable_req(port, tgt); if (rc) { - printk(KERN_ALERT PFX "enable session failed\n"); + printk(KERN_ERR PFX "enable session failed\n"); goto ofld_cmpl_err; } } @@ -1063,6 +1175,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, struct fcoe_kcqe *ofld_kcqe) { struct bnx2fc_rport *tgt; + struct bnx2fc_interface *interface; u32 conn_id; u32 context_id; @@ -1070,7 +1183,7 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, conn_id = ofld_kcqe->fcoe_conn_id; tgt = hba->tgt_ofld_list[conn_id]; if (!tgt) { - printk(KERN_ALERT PFX "ERROR:enbl_cmpl: No pending ofld req\n"); + printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n"); return; } @@ -1082,16 +1195,17 @@ static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, * and enable */ if (tgt->context_id != context_id) { - printk(KERN_ALERT PFX "context id mis-match\n"); + printk(KERN_ERR PFX "context id mis-match\n"); return; } - if (hba != tgt->port->priv) { - printk(KERN_ALERT PFX "bnx2fc-enbl_cmpl: HBA mis-match\n"); + interface = tgt->port->priv; + if (hba != interface->hba) { + printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n"); goto enbl_cmpl_err; } - if (ofld_kcqe->completion_status) { + if (ofld_kcqe->completion_status) goto enbl_cmpl_err; - } else { + else { /* enable successful - rport ready for issuing IOs */ set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); @@ -1114,14 +1228,14 @@ static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba, conn_id = disable_kcqe->fcoe_conn_id; tgt = hba->tgt_ofld_list[conn_id]; if (!tgt) { - printk(KERN_ALERT PFX "ERROR: disable_cmpl: No disable req\n"); + printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n"); return; } BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id); if (disable_kcqe->completion_status) { - printk(KERN_ALERT PFX "ERROR: Disable failed with cmpl status %d\n", + printk(KERN_ERR PFX "Disable failed with cmpl status %d\n", disable_kcqe->completion_status); return; } else { @@ -1143,14 +1257,14 @@ static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, conn_id = destroy_kcqe->fcoe_conn_id; tgt = hba->tgt_ofld_list[conn_id]; if (!tgt) { - printk(KERN_ALERT PFX "destroy_cmpl: No destroy req\n"); + printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n"); return; } BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id); if (destroy_kcqe->completion_status) { - printk(KERN_ALERT PFX "Destroy conn failed, cmpl status %d\n", + printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n", destroy_kcqe->completion_status); return; } else { @@ -1182,6 +1296,7 @@ static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code) break; case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION: printk(KERN_ERR PFX "init failure due to HSI mismatch\n"); + break; default: printk(KERN_ERR PFX "Unknown Error code %d\n", err_code); } @@ -1240,7 +1355,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], } else { printk(KERN_ERR PFX "DESTROY success\n"); } - hba->flags |= BNX2FC_FLAG_DESTROY_CMPL; + set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); wake_up_interruptible(&hba->destroy_wait); break; @@ -1262,7 +1377,7 @@ void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], case FCOE_KCQE_OPCODE_FCOE_ERROR: /* fall thru */ default: - printk(KERN_ALERT PFX "unknown opcode 0x%x\n", + printk(KERN_ERR PFX "unknown opcode 0x%x\n", kcqe->op_code); } } @@ -1305,7 +1420,8 @@ int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt) struct fcoe_port *port = tgt->port; u32 reg_off; resource_size_t reg_base; - struct bnx2fc_hba *hba = port->priv; + struct bnx2fc_interface *interface = port->priv; + struct bnx2fc_hba *hba = interface->hba; reg_base = pci_resource_start(hba->pcidev, BNX2X_DOORBELL_PCI_BAR); @@ -1344,6 +1460,96 @@ void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items) tgt->conn_db->rq_prod = tgt->rq_prod_idx; } +void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, + struct fcoe_task_ctx_entry *task, + struct bnx2fc_cmd *orig_io_req, + u32 offset) +{ + struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd; + struct bnx2fc_rport *tgt = seq_clnp_req->tgt; + struct bnx2fc_interface *interface = tgt->port->priv; + struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl; + struct fcoe_task_ctx_entry *orig_task; + struct fcoe_task_ctx_entry *task_page; + struct fcoe_ext_mul_sges_ctx *sgl; + u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP; + u8 orig_task_type; + u16 orig_xid = orig_io_req->xid; + u32 context_id = tgt->context_id; + u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma; + u32 orig_offset = offset; + int bd_count; + int orig_task_idx, index; + int i; + + memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); + + if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) + orig_task_type = FCOE_TASK_TYPE_WRITE; + else + orig_task_type = FCOE_TASK_TYPE_READ; + + /* Tx flags */ + task->txwr_rxrd.const_ctx.tx_flags = + FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP << + FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; + /* init flags */ + task->txwr_rxrd.const_ctx.init_flags = task_type << + FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; + task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << + FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; + task->rxwr_txrd.const_ctx.init_flags = context_id << + FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; + task->rxwr_txrd.const_ctx.init_flags = context_id << + FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; + + task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; + + task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0; + task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset; + + bd_count = orig_io_req->bd_tbl->bd_valid; + + /* obtain the appropriate bd entry from relative offset */ + for (i = 0; i < bd_count; i++) { + if (offset < bd[i].buf_len) + break; + offset -= bd[i].buf_len; + } + phys_addr += (i * sizeof(struct fcoe_bd_ctx)); + + if (orig_task_type == FCOE_TASK_TYPE_WRITE) { + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = + (u32)phys_addr; + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = + (u32)((u64)phys_addr >> 32); + task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = + bd_count; + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off = + offset; /* adjusted offset */ + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i; + } else { + orig_task_idx = orig_xid / BNX2FC_TASKS_PER_PAGE; + index = orig_xid % BNX2FC_TASKS_PER_PAGE; + + task_page = (struct fcoe_task_ctx_entry *) + interface->hba->task_ctx[orig_task_idx]; + orig_task = &(task_page[index]); + + /* Multiple SGEs were used for this IO */ + sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; + sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr; + sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32); + sgl->mul_sgl.sgl_size = bd_count; + sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */ + sgl->mul_sgl.cur_sge_idx = i; + + memset(&task->rxwr_only.rx_seq_ctx, 0, + sizeof(struct fcoe_rx_seq_ctx)); + task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset; + task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset; + } +} void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, struct fcoe_task_ctx_entry *task, u16 orig_xid) @@ -1360,7 +1566,12 @@ void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= + if (tgt->dev_type == TYPE_TAPE) + task->txwr_rxrd.const_ctx.init_flags |= + FCOE_TASK_DEV_TYPE_TAPE << + FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; + else + task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_DEV_TYPE_DISK << FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; @@ -1420,7 +1631,12 @@ void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req, /* init flags */ task->txwr_rxrd.const_ctx.init_flags = task_type << FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= + if (tgt->dev_type == TYPE_TAPE) + task->txwr_rxrd.const_ctx.init_flags |= + FCOE_TASK_DEV_TYPE_TAPE << + FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; + else + task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_DEV_TYPE_DISK << FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << @@ -1477,6 +1693,7 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, struct bnx2fc_rport *tgt = io_req->tgt; struct fcoe_cached_sge_ctx *cached_sge; struct fcoe_ext_mul_sges_ctx *sgl; + int dev_type = tgt->dev_type; u64 *fcp_cmnd; u64 tmp_fcp_cmnd[4]; u32 context_id; @@ -1494,20 +1711,40 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, task_type = FCOE_TASK_TYPE_READ; /* Tx only */ + bd_count = bd_tbl->bd_valid; if (task_type == FCOE_TASK_TYPE_WRITE) { - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = - (u32)bd_tbl->bd_tbl_dma; - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = - (u32)((u64)bd_tbl->bd_tbl_dma >> 32); - task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = - bd_tbl->bd_valid; + if ((dev_type == TYPE_DISK) && (bd_count == 1)) { + struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; + + task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo = + fcoe_bd_tbl->buf_addr_lo; + task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi = + fcoe_bd_tbl->buf_addr_hi; + task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem = + fcoe_bd_tbl->buf_len; + + task->txwr_rxrd.const_ctx.init_flags |= 1 << + FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; + } else { + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = + (u32)bd_tbl->bd_tbl_dma; + task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = + (u32)((u64)bd_tbl->bd_tbl_dma >> 32); + task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = + bd_tbl->bd_valid; + } } /*Tx Write Rx Read */ /* Init state to NORMAL */ - task->txwr_rxrd.const_ctx.init_flags = task_type << + task->txwr_rxrd.const_ctx.init_flags |= task_type << FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= + if (dev_type == TYPE_TAPE) + task->txwr_rxrd.const_ctx.init_flags |= + FCOE_TASK_DEV_TYPE_TAPE << + FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; + else + task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_DEV_TYPE_DISK << FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << @@ -1550,7 +1787,8 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge; sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; bd_count = bd_tbl->bd_valid; - if (task_type == FCOE_TASK_TYPE_READ) { + if (task_type == FCOE_TASK_TYPE_READ && + dev_type == TYPE_DISK) { if (bd_count == 1) { struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; @@ -1582,6 +1820,11 @@ void bnx2fc_init_task(struct bnx2fc_cmd *io_req, (u32)((u64)bd_tbl->bd_tbl_dma >> 32); sgl->mul_sgl.sgl_size = bd_count; } + } else { + sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; + sgl->mul_sgl.cur_sge_addr.hi = + (u32)((u64)bd_tbl->bd_tbl_dma >> 32); + sgl->mul_sgl.sgl_size = bd_count; } } |