1853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi/* 217d87c45b9042fa2f830c5a47cdfd3370bb60729Saurav Kashyap * bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver. 3853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * This file contains helper routines that handle ELS requests 4853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * and responses. 5853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * 6cf1221912fcdc2542509ef41543117ee86254d04Bhanu Prakash Gollapudi * Copyright (c) 2008 - 2013 Broadcom Corporation 717d87c45b9042fa2f830c5a47cdfd3370bb60729Saurav Kashyap * Copyright (c) 2014, QLogic Corporation 8853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * 9853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * This program is free software; you can redistribute it and/or modify 10853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * it under the terms of the GNU General Public License as published by 11853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * the Free Software Foundation. 12853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * 13853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 14853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi */ 15853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 16853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi#include "bnx2fc.h" 17853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 18853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, 19853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *arg); 20853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, 21853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *arg); 22853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, 23853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *data, u32 data_len, 24853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), 25853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec); 26853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 27853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg) 28853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 29853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_cmd *orig_io_req; 30853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_cmd *rrq_req; 31853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc = 0; 32853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 33853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BUG_ON(!cb_arg); 34853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rrq_req = cb_arg->io_req; 35853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi orig_io_req = cb_arg->aborted_io_req; 36853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BUG_ON(!orig_io_req); 37853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n", 38853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi orig_io_req->xid, rrq_req->xid); 39853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 40853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 41853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 42853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) { 43853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* 44853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * els req is timed out. cleanup the IO with FW and 45853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * drop the completion. Remove from active_cmd_queue. 46853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi */ 47853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n", 48853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rrq_req->xid); 49853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 50853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rrq_req->on_active_queue) { 51853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi list_del_init(&rrq_req->link); 52853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rrq_req->on_active_queue = 0; 53853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_cleanup(rrq_req); 54853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BUG_ON(rc); 55853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 56853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 57853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 58853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 59853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiint bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req) 60853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 61853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 62853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_els_rrq rrq; 63853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_rport *tgt = aborted_io_req->tgt; 64853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 65853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg = NULL; 66853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 sid = tgt->sid; 67853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 r_a_tov = lport->r_a_tov; 68853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi unsigned long start = jiffies; 69853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc; 70853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 71853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n", 72853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi aborted_io_req->xid); 73853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi memset(&rrq, 0, sizeof(rrq)); 74853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 75853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO); 76853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!cb_arg) { 77853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n"); 78853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -ENOMEM; 79853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto rrq_err; 80853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 81853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 82853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg->aborted_io_req = aborted_io_req; 83853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 84853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rrq.rrq_cmd = ELS_RRQ; 85853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hton24(rrq.rrq_s_id, sid); 86853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rrq.rrq_ox_id = htons(aborted_io_req->xid); 87619c5cb6885b936c44ae1422ef805b69c6291485Vlad Zolotarov rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id); 88853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 89853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiretry_rrq: 90853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq), 91853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_rrq_compl, cb_arg, 92853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi r_a_tov); 93853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc == -ENOMEM) { 94853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (time_after(jiffies, start + (10 * HZ))) { 95853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("rrq Failed\n"); 96853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = FAILED; 97853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto rrq_err; 98853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 99853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi msleep(20); 100853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto retry_rrq; 101853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 102853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudirrq_err: 103853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) { 104853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n", 105853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi aborted_io_req->xid); 106853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 107853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_lock_bh(&tgt->tgt_lock); 108853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release); 109853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_unlock_bh(&tgt->tgt_lock); 110853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 111853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return rc; 112853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 113853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 114853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg) 115853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 116853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_cmd *els_req; 117853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_rport *tgt; 118853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_mp_req *mp_req; 119853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fc_hdr; 120853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi unsigned char *buf; 121853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *resp_buf; 122853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 resp_len, hdr_len; 123853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u16 l2_oxid; 124853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int frame_len; 125853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc = 0; 126853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 127853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi l2_oxid = cb_arg->l2_oxid; 128853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid); 129853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 130853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req = cb_arg->io_req; 131853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) { 132853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* 133853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * els req is timed out. cleanup the IO with FW and 134853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi * drop the completion. libfc will handle the els timeout 135853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi */ 136853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (els_req->on_active_queue) { 137853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi list_del_init(&els_req->link); 138853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->on_active_queue = 0; 139853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_cleanup(els_req); 140853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BUG_ON(rc); 141853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 142853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto free_arg; 143853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 144853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 145853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi tgt = els_req->tgt; 146853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi mp_req = &(els_req->mp_req); 147853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_hdr = &(mp_req->resp_fc_hdr); 148853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi resp_len = mp_req->resp_len; 149853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi resp_buf = mp_req->resp_buf; 150853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 151853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); 152853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!buf) { 153853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "Unable to alloc mp buf\n"); 154853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto free_arg; 155853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 156853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hdr_len = sizeof(*fc_hdr); 157853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (hdr_len + resp_len > PAGE_SIZE) { 158853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "l2_els_compl: resp len is " 159853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi "beyond page size\n"); 160853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto free_buf; 161853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 162853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi memcpy(buf, fc_hdr, hdr_len); 163853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi memcpy(buf + hdr_len, resp_buf, resp_len); 164853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi frame_len = hdr_len + resp_len; 165853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 166853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid); 167853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 168853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudifree_buf: 169853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(buf); 170853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudifree_arg: 171853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 172853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 173853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 174853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiint bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp) 175853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 176853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_els_adisc *adisc; 177853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fh; 178853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg; 179853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 180853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 r_a_tov = lport->r_a_tov; 181853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc; 182853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 183853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fh = fc_frame_header_get(fp); 184853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 185853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!cb_arg) { 186853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n"); 187853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return -ENOMEM; 188853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 189853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 190853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 191853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 192853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid); 193853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi adisc = fc_frame_payload_get(fp, sizeof(*adisc)); 194853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* adisc is initialized by libfc */ 195853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc), 196853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 197853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) 198853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 199853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return rc; 200853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 201853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 202853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiint bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp) 203853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 204853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_els_logo *logo; 205853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fh; 206853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg; 207853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 208853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 r_a_tov = lport->r_a_tov; 209853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc; 210853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 211853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fh = fc_frame_header_get(fp); 212853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 213853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!cb_arg) { 214853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); 215853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return -ENOMEM; 216853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 217853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 218853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 219853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 220853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid); 221853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi logo = fc_frame_payload_get(fp, sizeof(*logo)); 222853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* logo is initialized by libfc */ 223853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo), 224853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 225853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) 226853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 227853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return rc; 228853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 229853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 230853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiint bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp) 231853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 232853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_els_rls *rls; 233853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fh; 234853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg; 235853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 236853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 r_a_tov = lport->r_a_tov; 237853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc; 238853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 239853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fh = fc_frame_header_get(fp); 240853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 241853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!cb_arg) { 242853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); 243853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return -ENOMEM; 244853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 245853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 246853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 247853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 248853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rls = fc_frame_payload_get(fp, sizeof(*rls)); 249853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* rls is initialized by libfc */ 250853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls), 251853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 252853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) 253853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kfree(cb_arg); 254853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return rc; 255853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 256853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 257744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudivoid bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) 258744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi{ 259744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_mp_req *mp_req; 260744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_frame_header *fc_hdr, *fh; 261744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_cmd *srr_req; 262744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_cmd *orig_io_req; 263744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_frame *fp; 264744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi unsigned char *buf; 265744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi void *resp_buf; 266744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 resp_len, hdr_len; 267744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u8 opcode; 268744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi int rc = 0; 269744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 270744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req = cb_arg->aborted_io_req; 271744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr_req = cb_arg->io_req; 272744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) { 273744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* SRR timedout */ 274744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr timed out, abort " 275744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "orig_io - 0x%x\n", 276744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->xid); 277744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(srr_req); 278744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 279744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " 280744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed. issue cleanup\n"); 281744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(srr_req); 282744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 28332c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || 28432c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { 28532c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx", 28632c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi orig_io_req->xid, orig_io_req->req_flags); 28732c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi goto srr_compl_done; 28832c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi } 289744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->srr_retry++; 290744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) { 291744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_rport *tgt = orig_io_req->tgt; 292744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_unlock_bh(&tgt->tgt_lock); 293744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_send_srr(orig_io_req, 294744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->srr_offset, 295744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->srr_rctl); 296744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_lock_bh(&tgt->tgt_lock); 297744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!rc) 298744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto srr_compl_done; 299744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 300744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 301744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(orig_io_req); 302744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 303744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " 304744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed xid = 0x%x. issue cleanup\n", 305744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->xid); 306744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 307744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 308744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto srr_compl_done; 309744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 31032c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || 31132c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { 31232c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx", 31332c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi orig_io_req->xid, orig_io_req->req_flags); 31432c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi goto srr_compl_done; 31532c30454507b4f5f00661ac12ddbcc150983b9ffBhanu Prakash Gollapudi } 316744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi mp_req = &(srr_req->mp_req); 317744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fc_hdr = &(mp_req->resp_fc_hdr); 318744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi resp_len = mp_req->resp_len; 319744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi resp_buf = mp_req->resp_buf; 320744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 321744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi hdr_len = sizeof(*fc_hdr); 322744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); 323744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!buf) { 324744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "srr buf: mem alloc failure\n"); 325744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto srr_compl_done; 326744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 327744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(buf, fc_hdr, hdr_len); 328744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(buf + hdr_len, resp_buf, resp_len); 329744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 330744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fp = fc_frame_alloc(NULL, resp_len); 331744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!fp) { 332744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "fc_frame_alloc failure\n"); 333744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto free_buf; 334744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 335744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 336744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fh = (struct fc_frame_header *) fc_frame_header_get(fp); 337744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* Copy FC Frame header and payload into the frame */ 338744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(fh, buf, hdr_len + resp_len); 339744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 340744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi opcode = fc_frame_payload_op(fp); 341744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi switch (opcode) { 342744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi case ELS_LS_ACC: 343744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "SRR success\n"); 344744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi break; 345744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi case ELS_LS_RJT: 346744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "SRR rejected\n"); 347744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(orig_io_req); 348744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 349744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " 350744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed xid = 0x%x. issue cleanup\n", 351744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->xid); 352744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 353744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 354744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi break; 355744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi default: 356744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n", 357744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi opcode); 358744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi break; 359744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 360744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fc_frame_free(fp); 361744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudifree_buf: 362744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kfree(buf); 363744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudisrr_compl_done: 364744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 365744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi} 366744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 367744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudivoid bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg) 368744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi{ 369744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_cmd *orig_io_req, *new_io_req; 370744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_cmd *rec_req; 371744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_mp_req *mp_req; 372744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_frame_header *fc_hdr, *fh; 373744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_els_ls_rjt *rjt; 374744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_els_rec_acc *acc; 375744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_rport *tgt; 376744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fcoe_err_report_entry *err_entry; 377744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct scsi_cmnd *sc_cmd; 378744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi enum fc_rctl r_ctl; 379744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi unsigned char *buf; 380744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi void *resp_buf; 381744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_frame *fp; 382744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u8 opcode; 383744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 offset; 384744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 e_stat; 385744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 resp_len, hdr_len; 386744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi int rc = 0; 387744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bool send_seq_clnp = false; 388744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bool abort_io = false; 389744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 390744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_MISC_DBG("Entered rec_compl callback\n"); 391744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rec_req = cb_arg->io_req; 392744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req = cb_arg->aborted_io_req; 393744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid); 394744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi tgt = orig_io_req->tgt; 395744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 396744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* Handle REC timeout case */ 397744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) { 398744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "timed out, abort " 399744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "orig_io - 0x%x\n", 400744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->xid); 401744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* els req is timed out. send abts for els */ 402744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(rec_req); 403744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 404744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " 405744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed. issue cleanup\n"); 406744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(rec_req); 407744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 408744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->rec_retry++; 409744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* REC timedout. send ABTS to the orig IO req */ 410744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (orig_io_req->rec_retry <= REC_RETRY_COUNT) { 411744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_unlock_bh(&tgt->tgt_lock); 412744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_send_rec(orig_io_req); 413744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_lock_bh(&tgt->tgt_lock); 414744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!rc) 415744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto rec_compl_done; 416744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 417744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(orig_io_req); 418744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 419744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " 420744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed xid = 0x%x. issue cleanup\n", 421744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->xid); 422744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 423744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 424744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto rec_compl_done; 425744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 426c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi 427c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { 428c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "completed" 429c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi "orig_io - 0x%x\n", 430c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi orig_io_req->xid); 431c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi goto rec_compl_done; 432c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi } 433c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { 434c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "abts in prog " 435c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi "orig_io - 0x%x\n", 436c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi orig_io_req->xid); 437c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi goto rec_compl_done; 438c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi } 439c1c16bd51a29eea8843f20161ddd32cddc524142Bhanu Prakash Gollapudi 440744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi mp_req = &(rec_req->mp_req); 441744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fc_hdr = &(mp_req->resp_fc_hdr); 442744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi resp_len = mp_req->resp_len; 443744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi acc = resp_buf = mp_req->resp_buf; 444744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 445744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi hdr_len = sizeof(*fc_hdr); 446744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 447744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); 448744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!buf) { 449744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "rec buf: mem alloc failure\n"); 450744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto rec_compl_done; 451744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 452744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(buf, fc_hdr, hdr_len); 453744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(buf + hdr_len, resp_buf, resp_len); 454744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 455744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fp = fc_frame_alloc(NULL, resp_len); 456744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!fp) { 457744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "fc_frame_alloc failure\n"); 458744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto free_buf; 459744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 460744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 461744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fh = (struct fc_frame_header *) fc_frame_header_get(fp); 462744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* Copy FC Frame header and payload into the frame */ 463744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memcpy(fh, buf, hdr_len + resp_len); 464744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 465744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi opcode = fc_frame_payload_op(fp); 466744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (opcode == ELS_LS_RJT) { 467744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "opcode is RJT\n"); 468744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rjt = fc_frame_payload_get(fp, sizeof(*rjt)); 469744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if ((rjt->er_reason == ELS_RJT_LOGIC || 470744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rjt->er_reason == ELS_RJT_UNAB) && 471744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rjt->er_explan == ELS_EXPL_OXID_RXID) { 472744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n"); 473744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi new_io_req = bnx2fc_cmd_alloc(tgt); 474744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!new_io_req) 475744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto abort_io; 476744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi new_io_req->sc_cmd = orig_io_req->sc_cmd; 477744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* cleanup orig_io_req that is with the FW */ 478744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi set_bit(BNX2FC_FLAG_CMD_LOST, 479744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi &orig_io_req->req_flags); 480744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 481744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* Post a new IO req with the same sc_cmd */ 482744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "Post IO request again\n"); 483744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_post_io_req(tgt, new_io_req); 484744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!rc) 485744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto free_frame; 486744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "REC: io post err\n"); 487744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 488744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudiabort_io: 489744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(orig_io_req); 490744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 491744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " 492744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi "failed. issue cleanup\n"); 493744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 494744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 495744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else if (opcode == ELS_LS_ACC) { 496744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* REVISIT: Check if the exchange is already aborted */ 497744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset = ntohl(acc->reca_fc4value); 498744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi e_stat = ntohl(acc->reca_e_stat); 499744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (e_stat & ESB_ST_SEQ_INIT) { 500744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "target has the seq init\n"); 501744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto free_frame; 502744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 503744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n", 504744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi e_stat, offset); 505744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* Seq initiative is with us */ 506744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi err_entry = (struct fcoe_err_report_entry *) 507744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi &orig_io_req->err_entry; 508744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi sc_cmd = orig_io_req->sc_cmd; 509744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { 510744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* SCSI WRITE command */ 511744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (offset == orig_io_req->data_xfer_len) { 512744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n"); 513744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* FCP_RSP lost */ 514744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_ctl = FC_RCTL_DD_CMD_STATUS; 515744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset = 0; 516744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else { 517744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* start transmitting from offset */ 518744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n"); 519744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi send_seq_clnp = true; 520744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_ctl = FC_RCTL_DD_DATA_DESC; 521744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (bnx2fc_initiate_seq_cleanup(orig_io_req, 522744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset, r_ctl)) 523744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi abort_io = true; 524744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* XFER_RDY */ 525744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 526744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else { 527744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* SCSI READ command */ 528744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (err_entry->data.rx_buf_off == 529744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->data_xfer_len) { 530744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* FCP_RSP lost */ 531744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "READ - resp lost\n"); 532744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_ctl = FC_RCTL_DD_CMD_STATUS; 533744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset = 0; 534744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else { 535744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* request retransmission from this offset */ 536744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi send_seq_clnp = true; 537744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset = err_entry->data.rx_buf_off; 538744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "RD DATA lost\n"); 539744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi /* FCP_DATA lost */ 540744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_ctl = FC_RCTL_DD_SOL_DATA; 541744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (bnx2fc_initiate_seq_cleanup(orig_io_req, 542744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi offset, r_ctl)) 543744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi abort_io = true; 544744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 545744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 546744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (abort_io) { 547744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_abts(orig_io_req); 548744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc != SUCCESS) { 549744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts" 550744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi " failed. issue cleanup\n"); 551744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_initiate_cleanup(orig_io_req); 552744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 553744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else if (!send_seq_clnp) { 554744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n"); 555744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_unlock_bh(&tgt->tgt_lock); 556744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); 557744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_lock_bh(&tgt->tgt_lock); 558744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 559744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc) { 560744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(rec_req, "Unable to send SRR" 561744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi " IO will abort\n"); 562744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 563744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 564744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 565744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudifree_frame: 566744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi fc_frame_free(fp); 567744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudifree_buf: 568744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kfree(buf); 569744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudirec_compl_done: 570744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 571744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kfree(cb_arg); 572744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi} 573744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 5746c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudiint bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) 5756c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi{ 576744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_els_rec rec; 577744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_rport *tgt = orig_io_req->tgt; 578744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 579744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_els_cb_arg *cb_arg = NULL; 580744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 sid = tgt->sid; 581744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 r_a_tov = lport->r_a_tov; 582744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi int rc; 583744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 584744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(orig_io_req, "Sending REC\n"); 585744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memset(&rec, 0, sizeof(rec)); 586744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 587744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 588744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!cb_arg) { 589744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n"); 590744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = -ENOMEM; 591744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto rec_err; 592744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 593744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_get(&orig_io_req->refcount); 594744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 595744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi cb_arg->aborted_io_req = orig_io_req; 596744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 597744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rec.rec_cmd = ELS_REC; 598744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi hton24(rec.rec_s_id, sid); 599744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rec.rec_ox_id = htons(orig_io_req->xid); 600744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); 601744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 602744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec), 603744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_rec_compl, cb_arg, 604744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_a_tov); 605744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudirec_err: 606744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc) { 607744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n"); 608744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_lock_bh(&tgt->tgt_lock); 609744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 610744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_unlock_bh(&tgt->tgt_lock); 611744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kfree(cb_arg); 612744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 613744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi return rc; 6146c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi} 6156c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi 6166c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudiint bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) 6176c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi{ 618744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fcp_srr srr; 619744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_rport *tgt = orig_io_req->tgt; 620744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct fc_lport *lport = tgt->rdata->local_port; 621744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi struct bnx2fc_els_cb_arg *cb_arg = NULL; 622744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi u32 r_a_tov = lport->r_a_tov; 623744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi int rc; 6246c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi 625744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n"); 626744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi memset(&srr, 0, sizeof(srr)); 6276c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi 628744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 629744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (!cb_arg) { 630744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n"); 631744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = -ENOMEM; 632744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi goto srr_err; 633744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } 634744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_get(&orig_io_req->refcount); 635744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 636744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi cb_arg->aborted_io_req = orig_io_req; 637744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 638744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr.srr_op = ELS_SRR; 639744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr.srr_ox_id = htons(orig_io_req->xid); 640744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); 641744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr.srr_rel_off = htonl(offset); 642744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi srr.srr_r_ctl = r_ctl; 643744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->srr_offset = offset; 644744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi orig_io_req->srr_rctl = r_ctl; 645744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 646744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr), 647744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi bnx2fc_srr_compl, cb_arg, 648744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi r_a_tov); 649744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudisrr_err: 650744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (rc) { 651744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n"); 652744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_lock_bh(&tgt->tgt_lock); 653744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 654744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi spin_unlock_bh(&tgt->tgt_lock); 655744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi kfree(cb_arg); 656744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi } else 657744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags); 658744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi 659744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi return rc; 660744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi} 6616c5a7ce4f176b641fd11e59be4df31ee3e6202ddBhanu Prakash Gollapudi 662853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, 663853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *data, u32 data_len, 664853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), 665853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec) 666853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 667853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_port *port = tgt->port; 668aea71a024914e8b5b8bed31256dae42195a0a207Bhanu Prakash Gollapudi struct bnx2fc_interface *interface = port->priv; 669853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_rport *rport = tgt->rport; 670853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = port->lport; 671853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_cmd *els_req; 672853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_mp_req *mp_req; 673853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fc_hdr; 674853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_task_ctx_entry *task; 675853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_task_ctx_entry *task_page; 676853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int rc = 0; 677853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi int task_idx, index; 678853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u32 did, sid; 679853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u16 xid; 680853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 681853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = fc_remote_port_chkready(rport); 682853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) { 683b2a554ff9ad5cdd8d00dac168f2bb3db7ccedb61Bhanu Prakash Gollapudi printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op); 684853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -EINVAL; 685853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 686853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 687853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (lport->state != LPORT_ST_READY || !(lport->link_up)) { 688b2a554ff9ad5cdd8d00dac168f2bb3db7ccedb61Bhanu Prakash Gollapudi printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op); 689853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -EINVAL; 690853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 691853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 692853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) || 693853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) { 694853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op); 695853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -EINVAL; 696853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 697853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 698853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS); 699853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!els_req) { 700853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -ENOMEM; 701853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 702853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 703853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 704853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->sc_cmd = NULL; 705853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->port = port; 706853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->tgt = tgt; 707853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_func = cb_func; 708853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi cb_arg->io_req = els_req; 709853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_arg = cb_arg; 710853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 711853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); 712853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = bnx2fc_init_mp_req(els_req); 713853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc == FAILED) { 714b2a554ff9ad5cdd8d00dac168f2bb3db7ccedb61Bhanu Prakash Gollapudi printk(KERN_ERR PFX "ELS MP request init failed\n"); 715853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_lock_bh(&tgt->tgt_lock); 716853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, bnx2fc_cmd_release); 717853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_unlock_bh(&tgt->tgt_lock); 718853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -ENOMEM; 719853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 720853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } else { 721853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* rc SUCCESS */ 722853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = 0; 723853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 724853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 725853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Set the data_xfer_len to the size of ELS payload */ 726853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi mp_req->req_len = data_len; 727853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->data_xfer_len = mp_req->req_len; 728853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 729853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Fill ELS Payload */ 730853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) { 731853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi memcpy(mp_req->req_buf, data, data_len); 732853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } else { 733b2a554ff9ad5cdd8d00dac168f2bb3db7ccedb61Bhanu Prakash Gollapudi printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op); 734853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_func = NULL; 735853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_arg = NULL; 736853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_lock_bh(&tgt->tgt_lock); 737853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, bnx2fc_cmd_release); 738853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_unlock_bh(&tgt->tgt_lock); 739853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi rc = -EINVAL; 740853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 741853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 742853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (rc) 743853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto els_err; 744853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 745853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Fill FC header */ 746853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_hdr = &(mp_req->req_fc_hdr); 747853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 748853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi did = tgt->rport->port_id; 749853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi sid = tgt->sid; 750853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 751744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi if (op == ELS_SRR) 752744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid, 753744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi FC_TYPE_FCP, FC_FC_FIRST_SEQ | 754744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); 755744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi else 756744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid, 757744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi FC_TYPE_ELS, FC_FC_FIRST_SEQ | 758744469542951d32979a8dcb1dbed560bfed1745eBhanu Prakash Gollapudi FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); 759853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 760853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Obtain exchange id */ 761853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi xid = els_req->xid; 762853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi task_idx = xid/BNX2FC_TASKS_PER_PAGE; 763853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi index = xid % BNX2FC_TASKS_PER_PAGE; 764853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 765853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Initialize task context for this IO request */ 766aea71a024914e8b5b8bed31256dae42195a0a207Bhanu Prakash Gollapudi task_page = (struct fcoe_task_ctx_entry *) 767aea71a024914e8b5b8bed31256dae42195a0a207Bhanu Prakash Gollapudi interface->hba->task_ctx[task_idx]; 768853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi task = &(task_page[index]); 769853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_init_mp_task(els_req, task); 770853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 771853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_lock_bh(&tgt->tgt_lock); 772853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 773853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { 774853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "initiate_els.. session not ready\n"); 775853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_func = NULL; 776853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_arg = NULL; 777853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, bnx2fc_cmd_release); 778853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_unlock_bh(&tgt->tgt_lock); 779853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return -EINVAL; 780853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 781853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 782853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (timer_msec) 783853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_cmd_timer_set(els_req, timer_msec); 784853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_add_2_sq(tgt, xid); 785853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 786853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->on_active_queue = 1; 787853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi list_add_tail(&els_req->link, &tgt->els_queue); 788853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 789853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Ring doorbell */ 790853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_ring_doorbell(tgt); 791853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi spin_unlock_bh(&tgt->tgt_lock); 792853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 793853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudiels_err: 794853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return rc; 795853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 796853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 797853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudivoid bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, 798853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_task_ctx_entry *task, u8 num_rq) 799853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 800853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct bnx2fc_mp_req *mp_req; 801853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fc_hdr; 802853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u64 *hdr; 803853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u64 *temp_hdr; 804853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 805853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x" 806853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi "cmd_type = %d\n", els_req->xid, els_req->cmd_type); 807853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 808853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE, 809853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi &els_req->req_flags)) { 810853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi BNX2FC_ELS_DBG("Timer context finished processing this " 811853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi "els - 0x%x\n", els_req->xid); 81225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* This IO doesn't receive cleanup completion */ 813853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, bnx2fc_cmd_release); 814853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return; 815853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 816853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 817853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Cancel the timeout_work, as we received the response */ 818853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (cancel_delayed_work(&els_req->timeout_work)) 819853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, 820853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi bnx2fc_cmd_release); /* drop timer hold */ 821853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 822853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (els_req->on_active_queue) { 823853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi list_del_init(&els_req->link); 824853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->on_active_queue = 0; 825853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 826853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 827853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi mp_req = &(els_req->mp_req); 828853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_hdr = &(mp_req->resp_fc_hdr); 829853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 830853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hdr = (u64 *)fc_hdr; 831853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi temp_hdr = (u64 *) 832619c5cb6885b936c44ae1422ef805b69c6291485Vlad Zolotarov &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; 833853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hdr[0] = cpu_to_be64(temp_hdr[0]); 834853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hdr[1] = cpu_to_be64(temp_hdr[1]); 835853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi hdr[2] = cpu_to_be64(temp_hdr[2]); 836853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 837619c5cb6885b936c44ae1422ef805b69c6291485Vlad Zolotarov mp_req->resp_len = 838619c5cb6885b936c44ae1422ef805b69c6291485Vlad Zolotarov task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; 839853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 840853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* Parse ELS response */ 841853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if ((els_req->cb_func) && (els_req->cb_arg)) { 842853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_func(els_req->cb_arg); 843853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi els_req->cb_arg = NULL; 844853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 845853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 846853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi kref_put(&els_req->refcount, bnx2fc_cmd_release); 847853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 848853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 849853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, 850853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *arg) 851853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 852853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_ctlr *fip = arg; 853853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_exch *exch = fc_seq_exch(seq); 854853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = exch->lp; 855853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u8 *mac; 856853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi u8 op; 857853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 858853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (IS_ERR(fp)) 859853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi goto done; 860853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 861853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi mac = fr_cb(fp)->granted_mac; 862853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (is_zero_ether_addr(mac)) { 863853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi op = fc_frame_payload_op(fp); 864853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (lport->vport) { 865853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (op == ELS_LS_RJT) { 866853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n"); 867853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_vport_terminate(lport->vport); 868853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_frame_free(fp); 869853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return; 870853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 871853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 872de9c05fafc296aa95b58352bad7f23f6199aa90dBhanu Prakash Gollapudi fcoe_ctlr_recv_flogi(fip, lport, fp); 873853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 874de9c05fafc296aa95b58352bad7f23f6199aa90dBhanu Prakash Gollapudi if (!is_zero_ether_addr(mac)) 875de9c05fafc296aa95b58352bad7f23f6199aa90dBhanu Prakash Gollapudi fip->update_mac(lport, mac); 876853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudidone: 877853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_lport_flogi_resp(seq, fp, lport); 878853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 879853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 880853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistatic void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, 881853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *arg) 882853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 883853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_ctlr *fip = arg; 884853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_exch *exch = fc_seq_exch(seq); 885853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_lport *lport = exch->lp; 886853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi static u8 zero_mac[ETH_ALEN] = { 0 }; 887853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 888853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (!IS_ERR(fp)) 889853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fip->update_mac(lport, zero_mac); 890853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fc_lport_logo_resp(seq, fp, lport); 891853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 892853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 893853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudistruct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, 894853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame *fp, unsigned int op, 895853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void (*resp)(struct fc_seq *, 896853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame *, 897853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *), 898853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi void *arg, u32 timeout) 899853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi{ 900853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fcoe_port *port = lport_priv(lport); 901aea71a024914e8b5b8bed31256dae42195a0a207Bhanu Prakash Gollapudi struct bnx2fc_interface *interface = port->priv; 902fd8f89027d816cb023edf6bfd4c744f194150a05Robert Love struct fcoe_ctlr *fip = bnx2fc_to_ctlr(interface); 903853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi struct fc_frame_header *fh = fc_frame_header_get(fp); 904853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi 905853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi switch (op) { 906853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi case ELS_FLOGI: 907853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi case ELS_FDISC: 908853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp, 909853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fip, timeout); 910853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi case ELS_LOGO: 911853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi /* only hook onto fabric logouts, not port logouts */ 912853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) 913853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi break; 914853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp, 915853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi fip, timeout); 916853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi } 917853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 918853e2bd2103aaa91d1ba1c0b57ba17628d836f03Bhanu Gollapudi} 919