]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ocs_fc/ocs_unsol.c
Update to bmake-20200902
[FreeBSD/FreeBSD.git] / sys / dev / ocs_fc / ocs_unsol.c
1 /*-
2  * Copyright (c) 2017 Broadcom. All rights reserved.
3  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions and the following disclaimer in the documentation
13  *    and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 /**
35  * @file
36  * Code to handle unsolicited received FC frames.
37  */
38
39 /*!
40  * @defgroup unsol Unsolicited Frame Handling
41  */
42
43 #include "ocs.h"
44 #include "ocs_els.h"
45 #include "ocs_fabric.h"
46 #include "ocs_device.h"
47
48 #define frame_printf(ocs, hdr, fmt, ...) \
49         do { \
50                 char s_id_text[16]; \
51                 ocs_node_fcid_display(fc_be24toh((hdr)->s_id), s_id_text, sizeof(s_id_text)); \
52                 ocs_log_debug(ocs, "[%06x.%s] %02x/%04x/%04x: " fmt, fc_be24toh((hdr)->d_id), s_id_text, \
53                         (hdr)->r_ctl, ocs_be16toh((hdr)->ox_id), ocs_be16toh((hdr)->rx_id), ##__VA_ARGS__); \
54         } while(0)
55
56 static int32_t ocs_unsol_process(ocs_t *ocs, ocs_hw_sequence_t *seq);
57 static int32_t ocs_dispatch_fcp_cmd(ocs_node_t *node, ocs_hw_sequence_t *seq);
58 static int32_t ocs_dispatch_fcp_cmd_auto_xfer_rdy(ocs_node_t *node, ocs_hw_sequence_t *seq);
59 static int32_t ocs_dispatch_fcp_data(ocs_node_t *node, ocs_hw_sequence_t *seq);
60 static int32_t ocs_domain_dispatch_frame(void *arg, ocs_hw_sequence_t *seq);
61 static int32_t ocs_node_dispatch_frame(void *arg, ocs_hw_sequence_t *seq);
62 static int32_t ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg);
63 static ocs_hw_sequence_t *ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock);
64 static uint8_t ocs_node_frames_held(void *arg);
65 static uint8_t ocs_domain_frames_held(void *arg);
66 static int32_t ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock);
67 static int32_t ocs_sframe_send_task_set_full_or_busy(ocs_node_t *node, ocs_hw_sequence_t *seq);
68
69 #define OCS_MAX_FRAMES_BEFORE_YEILDING 10000
70
71 /**
72  * @brief Process the RQ circular buffer and process the incoming frames.
73  *
74  * @param mythread Pointer to thread object.
75  *
76  * @return Returns 0 on success, or a non-zero value on failure.
77  */
78 int32_t
79 ocs_unsol_rq_thread(ocs_thread_t *mythread)
80 {
81         ocs_xport_rq_thread_info_t *thread_data = mythread->arg;
82         ocs_t *ocs = thread_data->ocs;
83         ocs_hw_sequence_t *seq;
84         uint32_t yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
85
86         ocs_log_debug(ocs, "%s running\n", mythread->name);
87         while (!ocs_thread_terminate_requested(mythread)) {
88                 seq = ocs_cbuf_get(thread_data->seq_cbuf, 100000);
89                 if (seq == NULL) {
90                         /* Prevent soft lockups by yielding the CPU */
91                         ocs_thread_yield(&thread_data->thread);
92                         yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
93                         continue;
94                 }
95                 /* Note: Always returns 0 */
96                 ocs_unsol_process((ocs_t*)seq->hw->os, seq);
97
98                 /* We have to prevent CPU soft lockups, so just yield the CPU after x frames. */
99                 if (--yield_count == 0) {
100                         ocs_thread_yield(&thread_data->thread);
101                         yield_count = OCS_MAX_FRAMES_BEFORE_YEILDING;
102                 }
103         }
104         ocs_log_debug(ocs, "%s exiting\n", mythread->name);
105         thread_data->thread_started = FALSE;
106         return 0;
107 }
108
109 /**
110  * @ingroup unsol
111  * @brief Callback function when aborting a port owned XRI
112  * exchanges.
113  *
114  * @return Returns 0.
115  */
116 static int32_t
117 ocs_unsol_abort_cb (ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, uint32_t ext, void *arg)
118 {
119         ocs_t *ocs = arg;
120         ocs_assert(hio, -1);
121         ocs_assert(arg, -1);
122         ocs_log_debug(ocs, "xri=0x%x tag=0x%x\n", hio->indicator, hio->reqtag);
123         ocs_hw_io_free(&ocs->hw, hio);
124         return 0;
125 }
126
127 /**
128  * @ingroup unsol
129  * @brief Abort either a RQ Pair auto XFER RDY XRI.
130  * @return Returns None.
131  */
132 static void
133 ocs_port_owned_abort(ocs_t *ocs, ocs_hw_io_t *hio)
134 {
135         ocs_hw_rtn_e hw_rc;
136         hw_rc = ocs_hw_io_abort(&ocs->hw, hio, FALSE,
137                                   ocs_unsol_abort_cb, ocs);
138         if((hw_rc == OCS_HW_RTN_IO_ABORT_IN_PROGRESS) ||
139            (hw_rc == OCS_HW_RTN_IO_PORT_OWNED_ALREADY_ABORTED)) {
140                 ocs_log_debug(ocs, "already aborted XRI 0x%x\n", hio->indicator);
141         } else if(hw_rc != OCS_HW_RTN_SUCCESS) {
142                 ocs_log_debug(ocs, "Error aborting XRI 0x%x status %d\n",
143                               hio->indicator, hw_rc);
144         }
145 }
146
147 /**
148  * @ingroup unsol
149  * @brief Handle unsolicited FC frames.
150  *
151  * <h3 class="desc">Description</h3>
152  * This function is called from the HW with unsolicited FC frames (FCP, ELS, BLS, etc.).
153  *
154  * @param arg Application-specified callback data.
155  * @param seq Header/payload sequence buffers.
156  *
157  * @return Returns 0 on success; or a negative error value on failure.
158  */
159
160 int32_t
161 ocs_unsolicited_cb(void *arg, ocs_hw_sequence_t *seq)
162 {
163         ocs_t *ocs = arg;
164         ocs_xport_t *xport = ocs->xport;
165         int32_t rc;
166
167         CPUTRACE("");
168
169         if (ocs->rq_threads == 0) {
170                 rc = ocs_unsol_process(ocs, seq);
171         } else {
172                 /* use the ox_id to dispatch this IO to a thread */
173                 fc_header_t *hdr = seq->header->dma.virt;
174                 uint32_t ox_id =  ocs_be16toh(hdr->ox_id);
175                 uint32_t thr_index = ox_id % ocs->rq_threads;
176
177                 rc = ocs_cbuf_put(xport->rq_thread_info[thr_index].seq_cbuf, seq);
178         }
179
180         if (rc) {
181                 ocs_hw_sequence_free(&ocs->hw, seq);
182         }
183
184         return 0;
185 }
186
187 /**
188  * @ingroup unsol
189  * @brief Handle unsolicited FC frames.
190  *
191  * <h3 class="desc">Description</h3>
192  * This function is called either from ocs_unsolicited_cb() or ocs_unsol_rq_thread().
193  *
194  * @param ocs Pointer to the ocs structure.
195  * @param seq Header/payload sequence buffers.
196  *
197  * @return Returns 0 on success, or a negative error value on failure.
198  */
199 static int32_t
200 ocs_unsol_process(ocs_t *ocs, ocs_hw_sequence_t *seq)
201 {
202         ocs_xport_fcfi_t *xport_fcfi = NULL;
203         ocs_domain_t *domain;
204         uint8_t seq_fcfi = seq->fcfi;
205
206         /* HW_WORKAROUND_OVERRIDE_FCFI_IN_SRB */
207         if (ocs->hw.workaround.override_fcfi) {
208                 if (ocs->hw.first_domain_idx > -1) {
209                         seq_fcfi = ocs->hw.first_domain_idx;
210                 }
211         }
212
213         /* Range check seq->fcfi */
214         if (seq_fcfi < ARRAY_SIZE(ocs->xport->fcfi)) {
215                 xport_fcfi = &ocs->xport->fcfi[seq_fcfi];
216         }
217
218         /* If the transport FCFI entry is NULL, then drop the frame */
219         if (xport_fcfi == NULL) {
220                 ocs_log_test(ocs, "FCFI %d is not valid, dropping frame\n", seq->fcfi);
221                 if (seq->hio != NULL) {
222                         ocs_port_owned_abort(ocs, seq->hio);
223                 }
224
225                 ocs_hw_sequence_free(&ocs->hw, seq);
226                 return 0;
227         }
228         domain = ocs_hw_domain_get(&ocs->hw, seq_fcfi);
229
230         /*
231          * If we are holding frames or the domain is not yet registered or
232          * there's already frames on the pending list,
233          * then add the new frame to pending list
234          */
235         if (domain == NULL ||
236             xport_fcfi->hold_frames ||
237             !ocs_list_empty(&xport_fcfi->pend_frames)) {
238                 ocs_lock(&xport_fcfi->pend_frames_lock);
239                         ocs_list_add_tail(&xport_fcfi->pend_frames, seq);
240                 ocs_unlock(&xport_fcfi->pend_frames_lock);
241
242                 if (domain != NULL) {
243                         /* immediately process pending frames */
244                         ocs_domain_process_pending(domain);
245                 }
246         } else {
247                 /*
248                  * We are not holding frames and pending list is empty, just process frame.
249                  * A non-zero return means the frame was not handled - so cleanup
250                  */
251                 if (ocs_domain_dispatch_frame(domain, seq)) {
252                         if (seq->hio != NULL) {
253                                 ocs_port_owned_abort(ocs, seq->hio);
254                         }
255                         ocs_hw_sequence_free(&ocs->hw, seq);
256                 }
257         }
258         return 0;
259 }
260
261 /**
262  * @ingroup unsol
263  * @brief Process pending frames queued to the given node.
264  *
265  * <h3 class="desc">Description</h3>
266  * Frames that are queued for the \c node are dispatched and returned
267  * to the RQ.
268  *
269  * @param node Node of the queued frames that are to be dispatched.
270  *
271  * @return Returns 0 on success, or a negative error value on failure.
272  */
273
274 int32_t
275 ocs_process_node_pending(ocs_node_t *node)
276 {
277         ocs_t *ocs = node->ocs;
278         ocs_hw_sequence_t *seq = NULL;
279         uint32_t pend_frames_processed = 0;
280
281         for (;;) {
282                 /* need to check for hold frames condition after each frame processed
283                  * because any given frame could cause a transition to a state that
284                  * holds frames
285                  */
286                 if (ocs_node_frames_held(node)) {
287                         break;
288                 }
289
290                 /* Get next frame/sequence */
291                 ocs_lock(&node->pend_frames_lock);
292                         seq = ocs_list_remove_head(&node->pend_frames);
293                         if (seq == NULL) {
294                                 pend_frames_processed = node->pend_frames_processed;
295                                 node->pend_frames_processed = 0;
296                                 ocs_unlock(&node->pend_frames_lock);
297                                 break;
298                         }
299                         node->pend_frames_processed++;
300                 ocs_unlock(&node->pend_frames_lock);
301
302                 /* now dispatch frame(s) to dispatch function */
303                 if (ocs_node_dispatch_frame(node, seq)) {
304                         if (seq->hio != NULL) {
305                                 ocs_port_owned_abort(ocs, seq->hio);
306                         }
307                         ocs_hw_sequence_free(&ocs->hw, seq);
308                 }
309         }
310
311         if (pend_frames_processed != 0) {
312                 ocs_log_debug(ocs, "%u node frames held and processed\n", pend_frames_processed);
313         }
314
315         return 0;
316 }
317
318 /**
319  * @ingroup unsol
320  * @brief Process pending frames queued to the given domain.
321  *
322  * <h3 class="desc">Description</h3>
323  * Frames that are queued for the \c domain are dispatched and
324  * returned to the RQ.
325  *
326  * @param domain Domain of the queued frames that are to be
327  *               dispatched.
328  *
329  * @return Returns 0 on success, or a negative error value on failure.
330  */
331
332 int32_t
333 ocs_domain_process_pending(ocs_domain_t *domain)
334 {
335         ocs_t *ocs = domain->ocs;
336         ocs_xport_fcfi_t *xport_fcfi;
337         ocs_hw_sequence_t *seq = NULL;
338         uint32_t pend_frames_processed = 0;
339
340         ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, -1);
341         xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
342
343         for (;;) {
344                 /* need to check for hold frames condition after each frame processed
345                  * because any given frame could cause a transition to a state that
346                  * holds frames
347                  */
348                 if (ocs_domain_frames_held(domain)) {
349                         break;
350                 }
351
352                 /* Get next frame/sequence */
353                 ocs_lock(&xport_fcfi->pend_frames_lock);
354                         seq = ocs_list_remove_head(&xport_fcfi->pend_frames);
355                         if (seq == NULL) {
356                                 pend_frames_processed = xport_fcfi->pend_frames_processed;
357                                 xport_fcfi->pend_frames_processed = 0;
358                                 ocs_unlock(&xport_fcfi->pend_frames_lock);
359                                 break;
360                         }
361                         xport_fcfi->pend_frames_processed++;
362                 ocs_unlock(&xport_fcfi->pend_frames_lock);
363
364                 /* now dispatch frame(s) to dispatch function */
365                 if (ocs_domain_dispatch_frame(domain, seq)) {
366                         if (seq->hio != NULL) {
367                                 ocs_port_owned_abort(ocs, seq->hio);
368                         }
369                         ocs_hw_sequence_free(&ocs->hw, seq);
370                 }
371         }
372         if (pend_frames_processed != 0) {
373                 ocs_log_debug(ocs, "%u domain frames held and processed\n", pend_frames_processed);
374         }
375         return 0;
376 }
377
378 /**
379  * @ingroup unsol
380  * @brief Purge given pending list
381  *
382  * <h3 class="desc">Description</h3>
383  * Frames that are queued on the given pending list are
384  * discarded and returned to the RQ.
385  *
386  * @param ocs Pointer to ocs object.
387  * @param pend_list Pending list to be purged.
388  * @param list_lock Lock that protects pending list.
389  *
390  * @return Returns 0 on success, or a negative error value on failure.
391  */
392
393 static int32_t
394 ocs_purge_pending(ocs_t *ocs, ocs_list_t *pend_list, ocs_lock_t *list_lock)
395 {
396         ocs_hw_sequence_t *frame;
397
398         for (;;) {
399                 frame = ocs_frame_next(pend_list, list_lock);
400                 if (frame == NULL) {
401                         break;
402                 }
403
404                 frame_printf(ocs, (fc_header_t*) frame->header->dma.virt, "Discarding held frame\n");
405                 if (frame->hio != NULL) {
406                         ocs_port_owned_abort(ocs, frame->hio);
407                 }
408                 ocs_hw_sequence_free(&ocs->hw, frame);
409         }
410
411         return 0;
412 }
413
414 /**
415  * @ingroup unsol
416  * @brief Purge node's pending (queued) frames.
417  *
418  * <h3 class="desc">Description</h3>
419  * Frames that are queued for the \c node are discarded and returned
420  * to the RQ.
421  *
422  * @param node Node of the queued frames that are to be discarded.
423  *
424  * @return Returns 0 on success, or a negative error value on failure.
425  */
426
427 int32_t
428 ocs_node_purge_pending(ocs_node_t *node)
429 {
430         return ocs_purge_pending(node->ocs, &node->pend_frames, &node->pend_frames_lock);
431 }
432
433 /**
434  * @ingroup unsol
435  * @brief Purge xport's pending (queued) frames.
436  *
437  * <h3 class="desc">Description</h3>
438  * Frames that are queued for the \c xport are discarded and
439  * returned to the RQ.
440  *
441  * @param domain Pointer to domain object.
442  *
443  * @return Returns 0 on success; or a negative error value on failure.
444  */
445
446 int32_t
447 ocs_domain_purge_pending(ocs_domain_t *domain)
448 {
449         ocs_t *ocs = domain->ocs;
450         ocs_xport_fcfi_t *xport_fcfi;
451
452         ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, -1);
453         xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
454         return ocs_purge_pending(domain->ocs,
455                                  &xport_fcfi->pend_frames,
456                                  &xport_fcfi->pend_frames_lock);
457 }
458
459 /**
460  * @ingroup unsol
461  * @brief Check if node's pending frames are held.
462  *
463  * @param arg Node for which the pending frame hold condition is
464  * checked.
465  *
466  * @return Returns 1 if node is holding pending frames, or 0
467  * if not.
468  */
469
470 static uint8_t
471 ocs_node_frames_held(void *arg)
472 {
473         ocs_node_t *node = (ocs_node_t *)arg;
474         return node->hold_frames;
475 }
476
477 /**
478  * @ingroup unsol
479  * @brief Check if domain's pending frames are held.
480  *
481  * @param arg Domain for which the pending frame hold condition is
482  * checked.
483  *
484  * @return Returns 1 if domain is holding pending frames, or 0
485  * if not.
486  */
487
488 static uint8_t
489 ocs_domain_frames_held(void *arg)
490 {
491         ocs_domain_t *domain = (ocs_domain_t *)arg;
492         ocs_t *ocs = domain->ocs;
493         ocs_xport_fcfi_t *xport_fcfi;
494
495         ocs_assert(domain != NULL, 1);
496         ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI, 1);
497         xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
498         return xport_fcfi->hold_frames;
499 }
500
501 /**
502  * @ingroup unsol
503  * @brief Globally (at xport level) hold unsolicited frames.
504  *
505  * <h3 class="desc">Description</h3>
506  * This function places a hold on processing unsolicited FC
507  * frames queued to the xport pending list.
508  *
509  * @param domain Pointer to domain object.
510  *
511  * @return Returns None.
512  */
513
514 void
515 ocs_domain_hold_frames(ocs_domain_t *domain)
516 {
517         ocs_t *ocs = domain->ocs;
518         ocs_xport_fcfi_t *xport_fcfi;
519
520         ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI);
521         xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
522         if (!xport_fcfi->hold_frames) {
523                 ocs_log_debug(domain->ocs, "hold frames set for FCFI %d\n",
524                               domain->fcf_indicator);
525                 xport_fcfi->hold_frames = 1;
526         }
527 }
528
529 /**
530  * @ingroup unsol
531  * @brief Clear hold on unsolicited frames.
532  *
533  * <h3 class="desc">Description</h3>
534  * This function clears the hold on processing unsolicited FC
535  * frames queued to the domain pending list.
536  *
537  * @param domain Pointer to domain object.
538  *
539  * @return Returns None.
540  */
541
542 void
543 ocs_domain_accept_frames(ocs_domain_t *domain)
544 {
545         ocs_t *ocs = domain->ocs;
546         ocs_xport_fcfi_t *xport_fcfi;
547
548         ocs_assert(domain->fcf_indicator < SLI4_MAX_FCFI);
549         xport_fcfi = &ocs->xport->fcfi[domain->fcf_indicator];
550         if (xport_fcfi->hold_frames == 1) {
551                 ocs_log_debug(domain->ocs, "hold frames cleared for FCFI %d\n",
552                               domain->fcf_indicator);
553         }
554         xport_fcfi->hold_frames = 0;
555         ocs_domain_process_pending(domain);
556 }
557
558 /**
559  * @ingroup unsol
560  * @brief Dispatch unsolicited FC frame.
561  *
562  * <h3 class="desc">Description</h3>
563  * This function processes an unsolicited FC frame queued at the
564  * domain level.
565  *
566  * @param arg Pointer to ocs object.
567  * @param seq Header/payload sequence buffers.
568  *
569  * @return Returns 0 if frame processed and RX buffers cleaned
570  * up appropriately, -1 if frame not handled.
571  */
572
573 static __inline int32_t
574 ocs_domain_dispatch_frame(void *arg, ocs_hw_sequence_t *seq)
575 {
576         ocs_domain_t *domain = (ocs_domain_t *)arg;
577         ocs_t *ocs = domain->ocs;
578         fc_header_t *hdr;
579         uint32_t s_id;
580         uint32_t d_id;
581         ocs_node_t *node = NULL;
582         ocs_sport_t *sport = NULL;
583
584         ocs_assert(seq->header, -1);
585         ocs_assert(seq->header->dma.virt, -1);
586         ocs_assert(seq->payload->dma.virt, -1);
587
588         hdr = seq->header->dma.virt;
589
590         /* extract the s_id and d_id */
591         s_id = fc_be24toh(hdr->s_id);
592         d_id = fc_be24toh(hdr->d_id);
593
594         sport = domain->sport;
595         if (sport == NULL) {
596                 frame_printf(ocs, hdr, "phy sport for FC ID 0x%06x is NULL, dropping frame\n", d_id);
597                 return -1;
598         }
599
600         if (sport->fc_id != d_id) {
601                 /* Not a physical port IO lookup sport associated with the npiv port */
602                 sport = ocs_sport_find(domain, d_id); /* Look up without lock */
603                 if (sport == NULL) {
604                         if (hdr->type == FC_TYPE_FCP) {
605                                 /* Drop frame */
606                                 ocs_log_warn(ocs, "unsolicited FCP frame with invalid d_id x%x, dropping\n",
607                                              d_id);
608                                 return -1;
609                         } else {
610                                 /* p2p will use this case */
611                                 sport = domain->sport;
612                         }
613                 }
614         }
615
616         /* Lookup the node given the remote s_id */
617         node = ocs_node_find(sport, s_id);
618
619         /* If not found, then create a new node */
620         if (node == NULL) {
621                 /* If this is solicited data or control based on R_CTL and there is no node context,
622                  * then we can drop the frame
623                  */
624                 if ((hdr->r_ctl == FC_RCTL_FC4_DATA) && (
625                     (hdr->info == FC_RCTL_INFO_SOL_DATA) || (hdr->info == FC_RCTL_INFO_SOL_CTRL))) {
626                         ocs_log_debug(ocs, "solicited data/ctrl frame without node, dropping\n");
627                         return -1;
628                 }
629                 node = ocs_node_alloc(sport, s_id, FALSE, FALSE);
630                 if (node == NULL) {
631                         ocs_log_err(ocs, "ocs_node_alloc() failed\n");
632                         return -1;
633                 }
634                 /* don't send PLOGI on ocs_d_init entry */
635                 ocs_node_init_device(node, FALSE);
636         }
637
638         if (node->hold_frames || !ocs_list_empty((&node->pend_frames))) {
639                 /* TODO: info log level
640                 frame_printf(ocs, hdr, "Holding frame\n");
641                 */
642                 /* add frame to node's pending list */
643                 ocs_lock(&node->pend_frames_lock);
644                         ocs_list_add_tail(&node->pend_frames, seq);
645                 ocs_unlock(&node->pend_frames_lock);
646
647                 return 0;
648         }
649
650         /* now dispatch frame to the node frame handler */
651         return ocs_node_dispatch_frame(node, seq);
652 }
653
654 /**
655  * @ingroup unsol
656  * @brief Dispatch a frame.
657  *
658  * <h3 class="desc">Description</h3>
659  * A frame is dispatched from the \c node to the handler.
660  *
661  * @param arg Node that originated the frame.
662  * @param seq Header/payload sequence buffers.
663  *
664  * @return Returns 0 if frame processed and RX buffers cleaned
665  * up appropriately, -1 if frame not handled.
666  */
667 static int32_t
668 ocs_node_dispatch_frame(void *arg, ocs_hw_sequence_t *seq)
669 {
670
671         fc_header_t *hdr = seq->header->dma.virt;
672         uint32_t port_id;
673         ocs_node_t *node = (ocs_node_t *)arg;
674         int32_t rc = -1;
675         int32_t sit_set = 0;
676
677         port_id = fc_be24toh(hdr->s_id);
678         ocs_assert(port_id == node->rnode.fc_id, -1);
679
680         if (fc_be24toh(hdr->f_ctl) & FC_FCTL_END_SEQUENCE) {
681                 /*if SIT is set */
682                 if (fc_be24toh(hdr->f_ctl) & FC_FCTL_SEQUENCE_INITIATIVE) {
683                         sit_set = 1;
684                 }
685                 switch (hdr->r_ctl) {
686                 case FC_RCTL_ELS:
687                         if (sit_set) {
688                                 rc = ocs_node_recv_els_frame(node, seq);
689                         }
690                         break;
691
692                 case FC_RCTL_BLS:
693                         if (sit_set) {
694                                 rc = ocs_node_recv_abts_frame(node, seq);
695                         }else {
696                                 rc = ocs_node_recv_bls_no_sit(node, seq);
697                         }
698                         break;
699
700                 case FC_RCTL_FC4_DATA:
701                         switch(hdr->type) {
702                         case FC_TYPE_FCP:
703                                 if (hdr->info == FC_RCTL_INFO_UNSOL_CMD) {
704                                         if (node->fcp_enabled) {
705                                                 if (sit_set) {
706                                                         rc = ocs_dispatch_fcp_cmd(node, seq);
707                                                 }else {
708                                                         /* send the auto xfer ready command */
709                                                         rc = ocs_dispatch_fcp_cmd_auto_xfer_rdy(node, seq);
710                                                 }
711                                         } else {
712                                                 rc = ocs_node_recv_fcp_cmd(node, seq);
713                                         }
714                                 } else if (hdr->info == FC_RCTL_INFO_SOL_DATA) {
715                                         if (sit_set) {
716                                                 rc = ocs_dispatch_fcp_data(node, seq);
717                                         }
718                                 }
719                                 break;
720                         case FC_TYPE_GS:
721                                 if (sit_set) {
722                                         rc = ocs_node_recv_ct_frame(node, seq);
723                                 }
724                                 break;
725                         default:
726                                 break;
727                         }
728                         break;
729                 }
730         } else {
731                 node_printf(node, "Dropping frame hdr = %08x %08x %08x %08x %08x %08x\n",
732                             ocs_htobe32(((uint32_t *)hdr)[0]),
733                             ocs_htobe32(((uint32_t *)hdr)[1]),
734                             ocs_htobe32(((uint32_t *)hdr)[2]),
735                             ocs_htobe32(((uint32_t *)hdr)[3]),
736                             ocs_htobe32(((uint32_t *)hdr)[4]),
737                             ocs_htobe32(((uint32_t *)hdr)[5]));
738         }
739         return rc;
740 }
741
742 /**
743  * @ingroup unsol
744  * @brief Dispatch unsolicited FCP frames (RQ Pair).
745  *
746  * <h3 class="desc">Description</h3>
747  * Dispatch unsolicited FCP frames (called from the device node state machine).
748  *
749  * @param io Pointer to the IO context.
750  * @param task_management_flags Task management flags from the FCP_CMND frame.
751  * @param node Node that originated the frame.
752  * @param lun 32-bit LUN from FCP_CMND frame.
753  *
754  * @return Returns None.
755  */
756
757 static void
758 ocs_dispatch_unsolicited_tmf(ocs_io_t *io, uint8_t task_management_flags, ocs_node_t *node, uint64_t lun)
759 {
760         uint32_t i;
761         struct {
762                 uint32_t mask;
763                 ocs_scsi_tmf_cmd_e cmd;
764         } tmflist[] = {
765                 {FCP_QUERY_TASK_SET,            OCS_SCSI_TMF_QUERY_TASK_SET},
766                 {FCP_ABORT_TASK_SET,            OCS_SCSI_TMF_ABORT_TASK_SET},
767                 {FCP_CLEAR_TASK_SET,            OCS_SCSI_TMF_CLEAR_TASK_SET},
768                 {FCP_QUERY_ASYNCHRONOUS_EVENT,  OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT},
769                 {FCP_LOGICAL_UNIT_RESET,        OCS_SCSI_TMF_LOGICAL_UNIT_RESET},
770                 {FCP_TARGET_RESET,              OCS_SCSI_TMF_TARGET_RESET},
771                 {FCP_CLEAR_ACA,                 OCS_SCSI_TMF_CLEAR_ACA}};
772
773         io->exp_xfer_len = 0; /* BUG 32235 */
774
775         for (i = 0; i < ARRAY_SIZE(tmflist); i ++) {
776                 if (tmflist[i].mask & task_management_flags) {
777                         io->tmf_cmd = tmflist[i].cmd;
778                         ocs_scsi_recv_tmf(io, lun, tmflist[i].cmd, NULL, 0);
779                         break;
780                 }
781         }
782         if (i == ARRAY_SIZE(tmflist)) {
783                 /* Not handled */
784                 node_printf(node, "TMF x%x rejected\n", task_management_flags);
785                 ocs_scsi_send_tmf_resp(io, OCS_SCSI_TMF_FUNCTION_REJECTED, NULL, ocs_fc_tmf_rejected_cb, NULL);
786         }
787 }
788
789 static int32_t
790 ocs_validate_fcp_cmd(ocs_t *ocs, ocs_hw_sequence_t *seq)
791 {
792         size_t          exp_payload_len = 0;
793         fcp_cmnd_iu_t *cmnd = seq->payload->dma.virt;
794         exp_payload_len = sizeof(fcp_cmnd_iu_t) - 16 + cmnd->additional_fcp_cdb_length;
795
796         /*
797          * If we received less than FCP_CMND_IU bytes, assume that the frame is
798          * corrupted in some way and drop it. This was seen when jamming the FCTL
799          * fill bytes field.
800          */
801         if (seq->payload->dma.len < exp_payload_len) {
802                 fc_header_t     *fchdr = seq->header->dma.virt;
803                 ocs_log_debug(ocs, "dropping ox_id %04x with payload length (%zd) less than expected (%zd)\n",
804                               ocs_be16toh(fchdr->ox_id), seq->payload->dma.len,
805                               exp_payload_len);
806                 return -1;
807         }
808         return 0;
809
810 }
811
812 static void
813 ocs_populate_io_fcp_cmd(ocs_io_t *io, fcp_cmnd_iu_t *cmnd, fc_header_t *fchdr, uint8_t sit)
814 {
815         uint32_t        *fcp_dl;
816         io->init_task_tag = ocs_be16toh(fchdr->ox_id);
817         /* note, tgt_task_tag, hw_tag  set when HW io is allocated */
818         fcp_dl = (uint32_t*)(&(cmnd->fcp_cdb_and_dl));
819         fcp_dl += cmnd->additional_fcp_cdb_length;
820         io->exp_xfer_len = ocs_be32toh(*fcp_dl);
821         io->transferred = 0;
822
823         /* The upper 7 bits of CS_CTL is the frame priority thru the SAN.
824          * Our assertion here is, the priority given to a frame containing
825          * the FCP cmd should be the priority given to ALL frames contained
826          * in that IO. Thus we need to save the incoming CS_CTL here.
827          */
828         if (fc_be24toh(fchdr->f_ctl) & FC_FCTL_PRIORITY_ENABLE) {
829                 io->cs_ctl = fchdr->cs_ctl;
830         } else {
831                 io->cs_ctl = 0;
832         }
833         io->seq_init = sit;
834 }
835
836 static uint32_t
837 ocs_get_flags_fcp_cmd(fcp_cmnd_iu_t *cmnd)
838 {
839         uint32_t flags = 0;
840         switch (cmnd->task_attribute) {
841         case FCP_TASK_ATTR_SIMPLE:
842                 flags |= OCS_SCSI_CMD_SIMPLE;
843                 break;
844         case FCP_TASK_ATTR_HEAD_OF_QUEUE:
845                 flags |= OCS_SCSI_CMD_HEAD_OF_QUEUE;
846                 break;
847         case FCP_TASK_ATTR_ORDERED:
848                 flags |= OCS_SCSI_CMD_ORDERED;
849                 break;
850         case FCP_TASK_ATTR_ACA:
851                 flags |= OCS_SCSI_CMD_ACA;
852                 break;
853         case FCP_TASK_ATTR_UNTAGGED:
854                 flags |= OCS_SCSI_CMD_UNTAGGED;
855                 break;
856         }
857         if (cmnd->wrdata)
858                 flags |= OCS_SCSI_CMD_DIR_IN;
859         if (cmnd->rddata)
860                 flags |= OCS_SCSI_CMD_DIR_OUT;
861
862         return flags;
863 }
864
865 /**
866  * @ingroup unsol
867  * @brief Dispatch unsolicited FCP_CMND frame.
868  *
869  * <h3 class="desc">Description</h3>
870  * Dispatch unsolicited FCP_CMND frame. RQ Pair mode - always
871  * used for RQ Pair mode since first burst is not supported.
872  *
873  * @param node Node that originated the frame.
874  * @param seq Header/payload sequence buffers.
875  *
876  * @return Returns 0 if frame processed and RX buffers cleaned
877  * up appropriately, -1 if frame not handled and RX buffers need
878  * to be returned.
879  */
880 static int32_t
881 ocs_dispatch_fcp_cmd(ocs_node_t *node, ocs_hw_sequence_t *seq)
882 {
883         ocs_t *ocs = node->ocs;
884         fc_header_t     *fchdr = seq->header->dma.virt;
885         fcp_cmnd_iu_t   *cmnd = NULL;
886         ocs_io_t        *io = NULL;
887         fc_vm_header_t  *vhdr;
888         uint8_t         df_ctl;
889         uint64_t        lun = UINT64_MAX;
890         int32_t         rc = 0;
891
892         ocs_assert(seq->payload, -1);
893         cmnd = seq->payload->dma.virt;
894
895         /* perform FCP_CMND validation check(s) */
896         if (ocs_validate_fcp_cmd(ocs, seq)) {
897                 return -1;
898         }
899
900         lun = CAM_EXTLUN_BYTE_SWIZZLE(be64dec(cmnd->fcp_lun));
901         if (lun == UINT64_MAX) {
902                 return -1;
903         }
904
905         io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_RESPONDER);
906         if (io == NULL) {
907                 uint32_t send_frame_capable;
908
909                 /* If we have SEND_FRAME capability, then use it to send task set full or busy */
910                 rc = ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &send_frame_capable);
911                 if ((rc == 0) && send_frame_capable) {
912                         rc = ocs_sframe_send_task_set_full_or_busy(node, seq);
913                         if (rc) {
914                                 ocs_log_test(ocs, "ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
915                         }
916                         return rc;
917                 }
918
919                 ocs_log_err(ocs, "IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->ox_id));
920                 return -1;
921         }
922         io->hw_priv = seq->hw_priv;
923
924         /* Check if the CMD has vmheader. */
925         io->app_id = 0;
926         df_ctl = fchdr->df_ctl;
927         if (df_ctl & FC_DFCTL_DEVICE_HDR_16_MASK) {
928                 uint32_t vmhdr_offset = 0;
929                 /* Presence of VMID. Get the vm header offset. */
930                 if (df_ctl & FC_DFCTL_ESP_HDR_MASK) {
931                         vmhdr_offset += FC_DFCTL_ESP_HDR_SIZE;
932                         ocs_log_err(ocs, "ESP Header present. Fix ESP Size.\n");
933                 }
934
935                 if (df_ctl & FC_DFCTL_NETWORK_HDR_MASK) {
936                         vmhdr_offset += FC_DFCTL_NETWORK_HDR_SIZE;
937                 }
938                 vhdr = (fc_vm_header_t *) ((char *)fchdr + sizeof(fc_header_t) + vmhdr_offset);
939                 io->app_id = ocs_be32toh(vhdr->src_vmid);
940         }
941
942         /* RQ pair, if we got here, SIT=1 */
943         ocs_populate_io_fcp_cmd(io, cmnd, fchdr, TRUE);
944
945         if (cmnd->task_management_flags) {
946                 ocs_dispatch_unsolicited_tmf(io, cmnd->task_management_flags, node, lun);
947         } else {
948                 uint32_t flags = ocs_get_flags_fcp_cmd(cmnd);
949
950                 /* can return failure for things like task set full and UAs,
951                  * no need to treat as a dropped frame if rc != 0
952                  */
953                 ocs_scsi_recv_cmd(io, lun, cmnd->fcp_cdb,
954                                   sizeof(cmnd->fcp_cdb) +
955                                   (cmnd->additional_fcp_cdb_length * sizeof(uint32_t)),
956                                   flags);
957         }
958
959         /* successfully processed, now return RX buffer to the chip */
960         ocs_hw_sequence_free(&ocs->hw, seq);
961         return 0;
962 }
963
964 /**
965  * @ingroup unsol
966  * @brief Dispatch unsolicited FCP_CMND frame (auto xfer rdy).
967  *
968  * <h3 class="desc">Description</h3>
969  * Dispatch unsolicited FCP_CMND frame that is assisted with auto xfer ready.
970  *
971  * @param node Node that originated the frame.
972  * @param seq Header/payload sequence buffers.
973  *
974  * @return Returns 0 if frame processed and RX buffers cleaned
975  * up appropriately, -1 if frame not handled and RX buffers need
976  * to be returned.
977  */
978 static int32_t
979 ocs_dispatch_fcp_cmd_auto_xfer_rdy(ocs_node_t *node, ocs_hw_sequence_t *seq)
980 {
981         ocs_t *ocs = node->ocs;
982         fc_header_t     *fchdr = seq->header->dma.virt;
983         fcp_cmnd_iu_t   *cmnd = NULL;
984         ocs_io_t        *io = NULL;
985         uint64_t        lun = UINT64_MAX;
986         int32_t         rc = 0;
987
988         ocs_assert(seq->payload, -1);
989         cmnd = seq->payload->dma.virt;
990
991         /* perform FCP_CMND validation check(s) */
992         if (ocs_validate_fcp_cmd(ocs, seq)) {
993                 return -1;
994         }
995
996         /* make sure first burst or auto xfer_rdy is enabled */
997         if (!seq->auto_xrdy) {
998                 node_printf(node, "IO is not Auto Xfr Rdy assisted, dropping FCP_CMND\n");
999                 return -1;
1000         }
1001
1002         lun = CAM_EXTLUN_BYTE_SWIZZLE(be64dec(cmnd->fcp_lun));
1003
1004         /* TODO should there be a check here for an error? Why do any of the
1005          * below if the LUN decode failed? */
1006         io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_RESPONDER);
1007         if (io == NULL) {
1008                 uint32_t send_frame_capable;
1009
1010                 /* If we have SEND_FRAME capability, then use it to send task set full or busy */
1011                 rc = ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &send_frame_capable);
1012                 if ((rc == 0) && send_frame_capable) {
1013                         rc = ocs_sframe_send_task_set_full_or_busy(node, seq);
1014                         if (rc) {
1015                                 ocs_log_test(ocs, "ocs_sframe_send_task_set_full_or_busy failed: %d\n", rc);
1016                         }
1017                         return rc;
1018                 }
1019
1020                 ocs_log_err(ocs, "IO allocation failed ox_id %04x\n", ocs_be16toh(fchdr->ox_id));
1021                 return -1;
1022         }
1023         io->hw_priv = seq->hw_priv;
1024
1025         /* RQ pair, if we got here, SIT=0 */
1026         ocs_populate_io_fcp_cmd(io, cmnd, fchdr, FALSE);
1027
1028         if (cmnd->task_management_flags) {
1029                 /* first burst command better not be a TMF */
1030                 ocs_log_err(ocs, "TMF flags set 0x%x\n", cmnd->task_management_flags);
1031                 ocs_scsi_io_free(io);
1032                 return -1;
1033         } else {
1034                 uint32_t flags = ocs_get_flags_fcp_cmd(cmnd);
1035
1036                 /* activate HW IO */
1037                 ocs_hw_io_activate_port_owned(&ocs->hw, seq->hio);
1038                 io->hio = seq->hio;
1039                 seq->hio->ul_io = io;
1040                 io->tgt_task_tag = seq->hio->indicator;
1041
1042                 /* Note: Data buffers are received in another call */
1043                 ocs_scsi_recv_cmd_first_burst(io, lun, cmnd->fcp_cdb,
1044                                               sizeof(cmnd->fcp_cdb) +
1045                                               (cmnd->additional_fcp_cdb_length * sizeof(uint32_t)),
1046                                               flags, NULL, 0);
1047         }
1048
1049         /* FCP_CMND processed, return RX buffer to the chip */
1050         ocs_hw_sequence_free(&ocs->hw, seq);
1051         return 0;
1052 }
1053
1054 /**
1055  * @ingroup unsol
1056  * @brief Dispatch FCP data frames for auto xfer ready.
1057  *
1058  * <h3 class="desc">Description</h3>
1059  * Dispatch unsolicited FCP data frames (auto xfer ready)
1060  * containing sequence initiative transferred (SIT=1).
1061  *
1062  * @param node Node that originated the frame.
1063  * @param seq Header/payload sequence buffers.
1064  *
1065  * @return Returns 0 if frame processed and RX buffers cleaned
1066  * up appropriately, -1 if frame not handled.
1067  */
1068
1069 static int32_t
1070 ocs_dispatch_fcp_data(ocs_node_t *node, ocs_hw_sequence_t *seq)
1071 {
1072         ocs_t *ocs = node->ocs;
1073         ocs_hw_t *hw = &ocs->hw;
1074         ocs_hw_io_t *hio = seq->hio;
1075         ocs_io_t        *io;
1076         ocs_dma_t fburst[1];
1077
1078         ocs_assert(seq->payload, -1);
1079         ocs_assert(hio, -1);
1080
1081         io = hio->ul_io;
1082         if (io == NULL) {
1083                 ocs_log_err(ocs, "data received for NULL io, xri=0x%x\n",
1084                             hio->indicator);
1085                 return -1;
1086         }
1087
1088         /*
1089          * We only support data completions for auto xfer ready. Make sure
1090          * this is a port owned XRI.
1091          */
1092         if (!ocs_hw_is_io_port_owned(hw, seq->hio)) {
1093                 ocs_log_err(ocs, "data received for host owned XRI, xri=0x%x\n",
1094                             hio->indicator);
1095                 return -1;
1096         }
1097
1098         /* For error statuses, pass the error to the target back end */
1099         if (seq->status != OCS_HW_UNSOL_SUCCESS) {
1100                 ocs_log_err(ocs, "data with status 0x%x received, xri=0x%x\n",
1101                             seq->status, hio->indicator);
1102
1103                 /*
1104                  * In this case, there is an existing, in-use HW IO that
1105                  * first may need to be aborted. Then, the backend will be
1106                  * notified of the error while waiting for the data.
1107                  */
1108                 ocs_port_owned_abort(ocs, seq->hio);
1109
1110                 /*
1111                  * HW IO has already been allocated and is waiting for data.
1112                  * Need to tell backend that an error has occurred.
1113                  */
1114                 ocs_scsi_recv_cmd_first_burst(io, 0, NULL, 0, OCS_SCSI_FIRST_BURST_ERR, NULL, 0);
1115                 return -1;
1116         }
1117
1118         /* sequence initiative has been transferred */
1119         io->seq_init = 1;
1120
1121         /* convert the array of pointers to the correct type, to send to backend */
1122         fburst[0] = seq->payload->dma;
1123
1124         /* the amount of first burst data was saved as "acculated sequence length" */
1125         io->transferred = seq->payload->dma.len;
1126
1127         if (ocs_scsi_recv_cmd_first_burst(io, 0, NULL, 0, 0,
1128                                           fburst, io->transferred)) {
1129                 ocs_log_err(ocs, "error passing first burst, xri=0x%x, oxid=0x%x\n",
1130                             hio->indicator, io->init_task_tag);
1131         }
1132
1133         /* Free the header and all the accumulated payload buffers */
1134         ocs_hw_sequence_free(&ocs->hw, seq);
1135         return 0;
1136 }
1137
1138 /**
1139  * @ingroup unsol
1140  * @brief Handle the callback for the TMF FUNCTION_REJECTED response.
1141  *
1142  * <h3 class="desc">Description</h3>
1143  * Handle the callback of a send TMF FUNCTION_REJECTED response request.
1144  *
1145  * @param io Pointer to the IO context.
1146  * @param scsi_status Status of the response.
1147  * @param flags Callback flags.
1148  * @param arg Callback argument.
1149  *
1150  * @return Returns 0 on success, or a negative error value on failure.
1151  */
1152
1153 static int32_t
1154 ocs_fc_tmf_rejected_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
1155 {
1156         ocs_scsi_io_free(io);
1157         return 0;
1158 }
1159
1160 /**
1161  * @brief Return next FC frame on node->pend_frames list
1162  *
1163  * The next FC frame on the node->pend_frames list is returned, or NULL
1164  * if the list is empty.
1165  *
1166  * @param pend_list Pending list to be purged.
1167  * @param list_lock Lock that protects pending list.
1168  *
1169  * @return Returns pointer to the next FC frame, or NULL if the pending frame list
1170  * is empty.
1171  */
1172 static ocs_hw_sequence_t *
1173 ocs_frame_next(ocs_list_t *pend_list, ocs_lock_t *list_lock)
1174 {
1175         ocs_hw_sequence_t *frame = NULL;
1176
1177         ocs_lock(list_lock);
1178                 frame = ocs_list_remove_head(pend_list);
1179         ocs_unlock(list_lock);
1180         return frame;
1181 }
1182
1183 /**
1184  * @brief Process send fcp response frame callback
1185  *
1186  * The function is called when the send FCP response posting has completed. Regardless
1187  * of the outcome, the sequence is freed.
1188  *
1189  * @param arg Pointer to originator frame sequence.
1190  * @param cqe Pointer to completion queue entry.
1191  * @param status Status of operation.
1192  *
1193  * @return None.
1194  */
1195 static void
1196 ocs_sframe_common_send_cb(void *arg, uint8_t *cqe, int32_t status)
1197 {
1198         ocs_hw_send_frame_context_t *ctx = arg;
1199         ocs_hw_t *hw = ctx->hw;
1200
1201         /* Free WQ completion callback */
1202         ocs_hw_reqtag_free(hw, ctx->wqcb);
1203
1204         /* Free sequence */
1205         ocs_hw_sequence_free(hw, ctx->seq);
1206 }
1207
1208 /**
1209  * @brief Send a frame, common code
1210  *
1211  * A frame is sent using SEND_FRAME, the R_CTL/F_CTL/TYPE may be specified, the payload is
1212  * sent as a single frame.
1213  *
1214  * Memory resources are allocated from RQ buffers contained in the passed in sequence data.
1215  *
1216  * @param node Pointer to node object.
1217  * @param seq Pointer to sequence object.
1218  * @param r_ctl R_CTL value to place in FC header.
1219  * @param info INFO value to place in FC header.
1220  * @param f_ctl F_CTL value to place in FC header.
1221  * @param type TYPE value to place in FC header.
1222  * @param payload Pointer to payload data
1223  * @param payload_len Length of payload in bytes.
1224  *
1225  * @return Returns 0 on success, or a negative error code value on failure.
1226  */
1227 static int32_t
1228 ocs_sframe_common_send(ocs_node_t *node, ocs_hw_sequence_t *seq, uint8_t r_ctl, uint8_t info, uint32_t f_ctl,
1229                        uint8_t type, void *payload, uint32_t payload_len)
1230 {
1231         ocs_t *ocs = node->ocs;
1232         ocs_hw_t *hw = &ocs->hw;
1233         ocs_hw_rtn_e rc = 0;
1234         fc_header_t *behdr = seq->header->dma.virt;
1235         fc_header_le_t hdr;
1236         uint32_t s_id = fc_be24toh(behdr->s_id);
1237         uint32_t d_id = fc_be24toh(behdr->d_id);
1238         uint16_t ox_id = ocs_be16toh(behdr->ox_id);
1239         uint16_t rx_id = ocs_be16toh(behdr->rx_id);
1240         ocs_hw_send_frame_context_t *ctx;
1241
1242         uint32_t heap_size = seq->payload->dma.size;
1243         uintptr_t heap_phys_base = seq->payload->dma.phys;
1244         uint8_t *heap_virt_base = seq->payload->dma.virt;
1245         uint32_t heap_offset = 0;
1246
1247         /* Build the FC header reusing the RQ header DMA buffer */
1248         ocs_memset(&hdr, 0, sizeof(hdr));
1249         hdr.d_id = s_id;                        /* send it back to whomever sent it to us */
1250         hdr.r_ctl = r_ctl;
1251         hdr.info = info;
1252         hdr.s_id = d_id;
1253         hdr.cs_ctl = 0;
1254         hdr.f_ctl = f_ctl;
1255         hdr.type = type;
1256         hdr.seq_cnt = 0;
1257         hdr.df_ctl = 0;
1258
1259         /*
1260          * send_frame_seq_id is an atomic, we just let it increment, while storing only
1261          * the low 8 bits to hdr->seq_id
1262          */
1263         hdr.seq_id = (uint8_t) ocs_atomic_add_return(&hw->send_frame_seq_id, 1);
1264
1265         hdr.rx_id = rx_id;
1266         hdr.ox_id = ox_id;
1267         hdr.parameter = 0;
1268
1269         /* Allocate and fill in the send frame request context */
1270         ctx = (void*)(heap_virt_base + heap_offset);
1271         heap_offset += sizeof(*ctx);
1272         ocs_assert(heap_offset < heap_size, -1);
1273         ocs_memset(ctx, 0, sizeof(*ctx));
1274
1275         /* Save sequence */
1276         ctx->seq = seq;
1277
1278         /* Allocate a response payload DMA buffer from the heap */
1279         ctx->payload.phys = heap_phys_base + heap_offset;
1280         ctx->payload.virt = heap_virt_base + heap_offset;
1281         ctx->payload.size = payload_len;
1282         ctx->payload.len = payload_len;
1283         heap_offset += payload_len;
1284         ocs_assert(heap_offset <= heap_size, -1);
1285
1286         /* Copy the payload in */
1287         ocs_memcpy(ctx->payload.virt, payload, payload_len);
1288
1289         /* Send */
1290         rc = ocs_hw_send_frame(&ocs->hw, (void*)&hdr, FC_SOFI3, FC_EOFT, &ctx->payload, ctx,
1291                                 ocs_sframe_common_send_cb, ctx);
1292         if (rc) {
1293                 ocs_log_test(ocs, "ocs_hw_send_frame failed: %d\n", rc);
1294         }
1295
1296         return rc ? -1 : 0;
1297 }
1298
1299 /**
1300  * @brief Send FCP response using SEND_FRAME
1301  *
1302  * The FCP response is send using the SEND_FRAME function.
1303  *
1304  * @param node Pointer to node object.
1305  * @param seq Pointer to inbound sequence.
1306  * @param rsp Pointer to response data.
1307  * @param rsp_len Length of response data, in bytes.
1308  *
1309  * @return Returns 0 on success, or a negative error code value on failure.
1310  */
1311 static int32_t
1312 ocs_sframe_send_fcp_rsp(ocs_node_t *node, ocs_hw_sequence_t *seq, void *rsp, uint32_t rsp_len)
1313 {
1314         return ocs_sframe_common_send(node, seq,
1315                                       FC_RCTL_FC4_DATA,
1316                                       FC_RCTL_INFO_CMD_STATUS,
1317                                       FC_FCTL_EXCHANGE_RESPONDER |
1318                                               FC_FCTL_LAST_SEQUENCE |
1319                                               FC_FCTL_END_SEQUENCE |
1320                                               FC_FCTL_SEQUENCE_INITIATIVE,
1321                                       FC_TYPE_FCP,
1322                                       rsp, rsp_len);
1323 }
1324
1325 /**
1326  * @brief Send task set full response
1327  *
1328  * Return a task set full or busy response using send frame.
1329  *
1330  * @param node Pointer to node object.
1331  * @param seq Pointer to originator frame sequence.
1332  *
1333  * @return Returns 0 on success, or a negative error code value on failure.
1334  */
1335 static int32_t
1336 ocs_sframe_send_task_set_full_or_busy(ocs_node_t *node, ocs_hw_sequence_t *seq)
1337 {
1338         fcp_rsp_iu_t fcprsp;
1339         fcp_cmnd_iu_t *fcpcmd = seq->payload->dma.virt;
1340         uint32_t *fcp_dl_ptr;
1341         uint32_t fcp_dl;
1342         int32_t rc = 0;
1343
1344         /* extract FCP_DL from FCP command*/
1345         fcp_dl_ptr = (uint32_t*)(&(fcpcmd->fcp_cdb_and_dl));
1346         fcp_dl_ptr += fcpcmd->additional_fcp_cdb_length;
1347         fcp_dl = ocs_be32toh(*fcp_dl_ptr);
1348
1349         /* construct task set full or busy response */
1350         ocs_memset(&fcprsp, 0, sizeof(fcprsp));
1351         ocs_lock(&node->active_ios_lock);
1352                 fcprsp.scsi_status = ocs_list_empty(&node->active_ios) ? SCSI_STATUS_BUSY : SCSI_STATUS_TASK_SET_FULL;
1353         ocs_unlock(&node->active_ios_lock);
1354         *((uint32_t*)&fcprsp.fcp_resid) = fcp_dl;
1355
1356         /* send it using send_frame */
1357         rc = ocs_sframe_send_fcp_rsp(node, seq, &fcprsp, sizeof(fcprsp) - sizeof(fcprsp.data));
1358         if (rc) {
1359                 ocs_log_test(node->ocs, "ocs_sframe_send_fcp_rsp failed: %d\n", rc);
1360         }
1361         return rc;
1362 }
1363
1364 /**
1365  * @brief Send BA_ACC using sent frame
1366  *
1367  * A BA_ACC is sent using SEND_FRAME
1368  *
1369  * @param node Pointer to node object.
1370  * @param seq Pointer to originator frame sequence.
1371  *
1372  * @return Returns 0 on success, or a negative error code value on failure.
1373  */
1374 int32_t
1375 ocs_sframe_send_bls_acc(ocs_node_t *node,  ocs_hw_sequence_t *seq)
1376 {
1377         fc_header_t *behdr = seq->header->dma.virt;
1378         uint16_t ox_id = ocs_be16toh(behdr->ox_id);
1379         uint16_t rx_id = ocs_be16toh(behdr->rx_id);
1380         fc_ba_acc_payload_t acc = {0};
1381
1382         acc.ox_id = ocs_htobe16(ox_id);
1383         acc.rx_id = ocs_htobe16(rx_id);
1384         acc.low_seq_cnt = UINT16_MAX;
1385         acc.high_seq_cnt = UINT16_MAX;
1386
1387         return ocs_sframe_common_send(node, seq,
1388                                       FC_RCTL_BLS,
1389                                       FC_RCTL_INFO_UNSOL_DATA,
1390                                       FC_FCTL_EXCHANGE_RESPONDER |
1391                                               FC_FCTL_LAST_SEQUENCE |
1392                                               FC_FCTL_END_SEQUENCE,
1393                                       FC_TYPE_BASIC_LINK,
1394                                       &acc, sizeof(acc));
1395 }