1 /* 2 * bnx2fc_els.c: Broadcom NetXtreme II Linux FCoE offload driver. 3 * This file contains helper routines that handle ELS requests 4 * and responses. 5 * 6 * Copyright (c) 2008 - 2010 Broadcom Corporation 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation. 11 * 12 * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) 13 */ 14 15 #include "bnx2fc.h" 16 17 static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, 18 void *arg); 19 static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, 20 void *arg); 21 static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, 22 void *data, u32 data_len, 23 void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), 24 struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec); 25 26 static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg) 27 { 28 struct bnx2fc_cmd *orig_io_req; 29 struct bnx2fc_cmd *rrq_req; 30 int rc = 0; 31 32 BUG_ON(!cb_arg); 33 rrq_req = cb_arg->io_req; 34 orig_io_req = cb_arg->aborted_io_req; 35 BUG_ON(!orig_io_req); 36 BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n", 37 orig_io_req->xid, rrq_req->xid); 38 39 kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); 40 41 if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) { 42 /* 43 * els req is timed out. cleanup the IO with FW and 44 * drop the completion. Remove from active_cmd_queue. 45 */ 46 BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n", 47 rrq_req->xid); 48 49 if (rrq_req->on_active_queue) { 50 list_del_init(&rrq_req->link); 51 rrq_req->on_active_queue = 0; 52 rc = bnx2fc_initiate_cleanup(rrq_req); 53 BUG_ON(rc); 54 } 55 } 56 kfree(cb_arg); 57 } 58 int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req) 59 { 60 61 struct fc_els_rrq rrq; 62 struct bnx2fc_rport *tgt = aborted_io_req->tgt; 63 struct fc_lport *lport = tgt->rdata->local_port; 64 struct bnx2fc_els_cb_arg *cb_arg = NULL; 65 u32 sid = tgt->sid; 66 u32 r_a_tov = lport->r_a_tov; 67 unsigned long start = jiffies; 68 int rc; 69 70 BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n", 71 aborted_io_req->xid); 72 memset(&rrq, 0, sizeof(rrq)); 73 74 cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO); 75 if (!cb_arg) { 76 printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n"); 77 rc = -ENOMEM; 78 goto rrq_err; 79 } 80 81 cb_arg->aborted_io_req = aborted_io_req; 82 83 rrq.rrq_cmd = ELS_RRQ; 84 hton24(rrq.rrq_s_id, sid); 85 rrq.rrq_ox_id = htons(aborted_io_req->xid); 86 rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id); 87 88 retry_rrq: 89 rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq), 90 bnx2fc_rrq_compl, cb_arg, 91 r_a_tov); 92 if (rc == -ENOMEM) { 93 if (time_after(jiffies, start + (10 * HZ))) { 94 BNX2FC_ELS_DBG("rrq Failed\n"); 95 rc = FAILED; 96 goto rrq_err; 97 } 98 msleep(20); 99 goto retry_rrq; 100 } 101 rrq_err: 102 if (rc) { 103 BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n", 104 aborted_io_req->xid); 105 kfree(cb_arg); 106 spin_lock_bh(&tgt->tgt_lock); 107 kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release); 108 spin_unlock_bh(&tgt->tgt_lock); 109 } 110 return rc; 111 } 112 113 static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg) 114 { 115 struct bnx2fc_cmd *els_req; 116 struct bnx2fc_rport *tgt; 117 struct bnx2fc_mp_req *mp_req; 118 struct fc_frame_header *fc_hdr; 119 unsigned char *buf; 120 void *resp_buf; 121 u32 resp_len, hdr_len; 122 u16 l2_oxid; 123 int frame_len; 124 int rc = 0; 125 126 l2_oxid = cb_arg->l2_oxid; 127 BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid); 128 129 els_req = cb_arg->io_req; 130 if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) { 131 /* 132 * els req is timed out. cleanup the IO with FW and 133 * drop the completion. libfc will handle the els timeout 134 */ 135 if (els_req->on_active_queue) { 136 list_del_init(&els_req->link); 137 els_req->on_active_queue = 0; 138 rc = bnx2fc_initiate_cleanup(els_req); 139 BUG_ON(rc); 140 } 141 goto free_arg; 142 } 143 144 tgt = els_req->tgt; 145 mp_req = &(els_req->mp_req); 146 fc_hdr = &(mp_req->resp_fc_hdr); 147 resp_len = mp_req->resp_len; 148 resp_buf = mp_req->resp_buf; 149 150 buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); 151 if (!buf) { 152 printk(KERN_ERR PFX "Unable to alloc mp buf\n"); 153 goto free_arg; 154 } 155 hdr_len = sizeof(*fc_hdr); 156 if (hdr_len + resp_len > PAGE_SIZE) { 157 printk(KERN_ERR PFX "l2_els_compl: resp len is " 158 "beyond page size\n"); 159 goto free_buf; 160 } 161 memcpy(buf, fc_hdr, hdr_len); 162 memcpy(buf + hdr_len, resp_buf, resp_len); 163 frame_len = hdr_len + resp_len; 164 165 bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid); 166 167 free_buf: 168 kfree(buf); 169 free_arg: 170 kfree(cb_arg); 171 } 172 173 int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp) 174 { 175 struct fc_els_adisc *adisc; 176 struct fc_frame_header *fh; 177 struct bnx2fc_els_cb_arg *cb_arg; 178 struct fc_lport *lport = tgt->rdata->local_port; 179 u32 r_a_tov = lport->r_a_tov; 180 int rc; 181 182 fh = fc_frame_header_get(fp); 183 cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 184 if (!cb_arg) { 185 printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n"); 186 return -ENOMEM; 187 } 188 189 cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 190 191 BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid); 192 adisc = fc_frame_payload_get(fp, sizeof(*adisc)); 193 /* adisc is initialized by libfc */ 194 rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc), 195 bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 196 if (rc) 197 kfree(cb_arg); 198 return rc; 199 } 200 201 int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp) 202 { 203 struct fc_els_logo *logo; 204 struct fc_frame_header *fh; 205 struct bnx2fc_els_cb_arg *cb_arg; 206 struct fc_lport *lport = tgt->rdata->local_port; 207 u32 r_a_tov = lport->r_a_tov; 208 int rc; 209 210 fh = fc_frame_header_get(fp); 211 cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 212 if (!cb_arg) { 213 printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); 214 return -ENOMEM; 215 } 216 217 cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 218 219 BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid); 220 logo = fc_frame_payload_get(fp, sizeof(*logo)); 221 /* logo is initialized by libfc */ 222 rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo), 223 bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 224 if (rc) 225 kfree(cb_arg); 226 return rc; 227 } 228 229 int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp) 230 { 231 struct fc_els_rls *rls; 232 struct fc_frame_header *fh; 233 struct bnx2fc_els_cb_arg *cb_arg; 234 struct fc_lport *lport = tgt->rdata->local_port; 235 u32 r_a_tov = lport->r_a_tov; 236 int rc; 237 238 fh = fc_frame_header_get(fp); 239 cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); 240 if (!cb_arg) { 241 printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); 242 return -ENOMEM; 243 } 244 245 cb_arg->l2_oxid = ntohs(fh->fh_ox_id); 246 247 rls = fc_frame_payload_get(fp, sizeof(*rls)); 248 /* rls is initialized by libfc */ 249 rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls), 250 bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); 251 if (rc) 252 kfree(cb_arg); 253 return rc; 254 } 255 256 static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, 257 void *data, u32 data_len, 258 void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), 259 struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec) 260 { 261 struct fcoe_port *port = tgt->port; 262 struct bnx2fc_hba *hba = port->priv; 263 struct fc_rport *rport = tgt->rport; 264 struct fc_lport *lport = port->lport; 265 struct bnx2fc_cmd *els_req; 266 struct bnx2fc_mp_req *mp_req; 267 struct fc_frame_header *fc_hdr; 268 struct fcoe_task_ctx_entry *task; 269 struct fcoe_task_ctx_entry *task_page; 270 int rc = 0; 271 int task_idx, index; 272 u32 did, sid; 273 u16 xid; 274 275 rc = fc_remote_port_chkready(rport); 276 if (rc) { 277 printk(KERN_ALERT PFX "els 0x%x: rport not ready\n", op); 278 rc = -EINVAL; 279 goto els_err; 280 } 281 if (lport->state != LPORT_ST_READY || !(lport->link_up)) { 282 printk(KERN_ALERT PFX "els 0x%x: link is not ready\n", op); 283 rc = -EINVAL; 284 goto els_err; 285 } 286 if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) || 287 (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) { 288 printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op); 289 rc = -EINVAL; 290 goto els_err; 291 } 292 els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS); 293 if (!els_req) { 294 rc = -ENOMEM; 295 goto els_err; 296 } 297 298 els_req->sc_cmd = NULL; 299 els_req->port = port; 300 els_req->tgt = tgt; 301 els_req->cb_func = cb_func; 302 cb_arg->io_req = els_req; 303 els_req->cb_arg = cb_arg; 304 305 mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); 306 rc = bnx2fc_init_mp_req(els_req); 307 if (rc == FAILED) { 308 printk(KERN_ALERT PFX "ELS MP request init failed\n"); 309 spin_lock_bh(&tgt->tgt_lock); 310 kref_put(&els_req->refcount, bnx2fc_cmd_release); 311 spin_unlock_bh(&tgt->tgt_lock); 312 rc = -ENOMEM; 313 goto els_err; 314 } else { 315 /* rc SUCCESS */ 316 rc = 0; 317 } 318 319 /* Set the data_xfer_len to the size of ELS payload */ 320 mp_req->req_len = data_len; 321 els_req->data_xfer_len = mp_req->req_len; 322 323 /* Fill ELS Payload */ 324 if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) { 325 memcpy(mp_req->req_buf, data, data_len); 326 } else { 327 printk(KERN_ALERT PFX "Invalid ELS op 0x%x\n", op); 328 els_req->cb_func = NULL; 329 els_req->cb_arg = NULL; 330 spin_lock_bh(&tgt->tgt_lock); 331 kref_put(&els_req->refcount, bnx2fc_cmd_release); 332 spin_unlock_bh(&tgt->tgt_lock); 333 rc = -EINVAL; 334 } 335 336 if (rc) 337 goto els_err; 338 339 /* Fill FC header */ 340 fc_hdr = &(mp_req->req_fc_hdr); 341 342 did = tgt->rport->port_id; 343 sid = tgt->sid; 344 345 __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid, 346 FC_TYPE_ELS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | 347 FC_FC_SEQ_INIT, 0); 348 349 /* Obtain exchange id */ 350 xid = els_req->xid; 351 task_idx = xid/BNX2FC_TASKS_PER_PAGE; 352 index = xid % BNX2FC_TASKS_PER_PAGE; 353 354 /* Initialize task context for this IO request */ 355 task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx]; 356 task = &(task_page[index]); 357 bnx2fc_init_mp_task(els_req, task); 358 359 spin_lock_bh(&tgt->tgt_lock); 360 361 if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { 362 printk(KERN_ERR PFX "initiate_els.. session not ready\n"); 363 els_req->cb_func = NULL; 364 els_req->cb_arg = NULL; 365 kref_put(&els_req->refcount, bnx2fc_cmd_release); 366 spin_unlock_bh(&tgt->tgt_lock); 367 return -EINVAL; 368 } 369 370 if (timer_msec) 371 bnx2fc_cmd_timer_set(els_req, timer_msec); 372 bnx2fc_add_2_sq(tgt, xid); 373 374 els_req->on_active_queue = 1; 375 list_add_tail(&els_req->link, &tgt->els_queue); 376 377 /* Ring doorbell */ 378 bnx2fc_ring_doorbell(tgt); 379 spin_unlock_bh(&tgt->tgt_lock); 380 381 els_err: 382 return rc; 383 } 384 385 void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, 386 struct fcoe_task_ctx_entry *task, u8 num_rq) 387 { 388 struct bnx2fc_mp_req *mp_req; 389 struct fc_frame_header *fc_hdr; 390 u64 *hdr; 391 u64 *temp_hdr; 392 393 BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x" 394 "cmd_type = %d\n", els_req->xid, els_req->cmd_type); 395 396 if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE, 397 &els_req->req_flags)) { 398 BNX2FC_ELS_DBG("Timer context finished processing this " 399 "els - 0x%x\n", els_req->xid); 400 /* This IO doesn't receive cleanup completion */ 401 kref_put(&els_req->refcount, bnx2fc_cmd_release); 402 return; 403 } 404 405 /* Cancel the timeout_work, as we received the response */ 406 if (cancel_delayed_work(&els_req->timeout_work)) 407 kref_put(&els_req->refcount, 408 bnx2fc_cmd_release); /* drop timer hold */ 409 410 if (els_req->on_active_queue) { 411 list_del_init(&els_req->link); 412 els_req->on_active_queue = 0; 413 } 414 415 mp_req = &(els_req->mp_req); 416 fc_hdr = &(mp_req->resp_fc_hdr); 417 418 hdr = (u64 *)fc_hdr; 419 temp_hdr = (u64 *) 420 &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; 421 hdr[0] = cpu_to_be64(temp_hdr[0]); 422 hdr[1] = cpu_to_be64(temp_hdr[1]); 423 hdr[2] = cpu_to_be64(temp_hdr[2]); 424 425 mp_req->resp_len = 426 task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; 427 428 /* Parse ELS response */ 429 if ((els_req->cb_func) && (els_req->cb_arg)) { 430 els_req->cb_func(els_req->cb_arg); 431 els_req->cb_arg = NULL; 432 } 433 434 kref_put(&els_req->refcount, bnx2fc_cmd_release); 435 } 436 437 static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, 438 void *arg) 439 { 440 struct fcoe_ctlr *fip = arg; 441 struct fc_exch *exch = fc_seq_exch(seq); 442 struct fc_lport *lport = exch->lp; 443 u8 *mac; 444 struct fc_frame_header *fh; 445 u8 op; 446 447 if (IS_ERR(fp)) 448 goto done; 449 450 mac = fr_cb(fp)->granted_mac; 451 if (is_zero_ether_addr(mac)) { 452 fh = fc_frame_header_get(fp); 453 if (fh->fh_type != FC_TYPE_ELS) { 454 printk(KERN_ERR PFX "bnx2fc_flogi_resp:" 455 "fh_type != FC_TYPE_ELS\n"); 456 fc_frame_free(fp); 457 return; 458 } 459 op = fc_frame_payload_op(fp); 460 if (lport->vport) { 461 if (op == ELS_LS_RJT) { 462 printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n"); 463 fc_vport_terminate(lport->vport); 464 fc_frame_free(fp); 465 return; 466 } 467 } 468 if (fcoe_ctlr_recv_flogi(fip, lport, fp)) { 469 fc_frame_free(fp); 470 return; 471 } 472 } 473 fip->update_mac(lport, mac); 474 done: 475 fc_lport_flogi_resp(seq, fp, lport); 476 } 477 478 static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, 479 void *arg) 480 { 481 struct fcoe_ctlr *fip = arg; 482 struct fc_exch *exch = fc_seq_exch(seq); 483 struct fc_lport *lport = exch->lp; 484 static u8 zero_mac[ETH_ALEN] = { 0 }; 485 486 if (!IS_ERR(fp)) 487 fip->update_mac(lport, zero_mac); 488 fc_lport_logo_resp(seq, fp, lport); 489 } 490 491 struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, 492 struct fc_frame *fp, unsigned int op, 493 void (*resp)(struct fc_seq *, 494 struct fc_frame *, 495 void *), 496 void *arg, u32 timeout) 497 { 498 struct fcoe_port *port = lport_priv(lport); 499 struct bnx2fc_hba *hba = port->priv; 500 struct fcoe_ctlr *fip = &hba->ctlr; 501 struct fc_frame_header *fh = fc_frame_header_get(fp); 502 503 switch (op) { 504 case ELS_FLOGI: 505 case ELS_FDISC: 506 return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp, 507 fip, timeout); 508 case ELS_LOGO: 509 /* only hook onto fabric logouts, not port logouts */ 510 if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) 511 break; 512 return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp, 513 fip, timeout); 514 } 515 return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); 516 } 517