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 * OCS Linux SCSI API base driver implementation.
37 */
38
39 /**
40 * @defgroup scsi_api_base SCSI Base Target/Initiator
41 */
42
43
44 #include "ocs.h"
45 #include "ocs_els.h"
46 #include "ocs_scsi.h"
47 #if defined(OCS_ENABLE_VPD_SUPPORT)
48 #include "ocs_vpd.h"
49 #endif
50 #include "ocs_utils.h"
51 #include "ocs_device.h"
52
53 #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]"
54 #define SCSI_ITT_SIZE(ocs) ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8)
55
56 #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag
57
58 #define enable_tsend_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TSEND) == 0)
59 #define enable_treceive_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TRECEIVE) == 0)
60
61 #define scsi_io_printf(io, fmt, ...) ocs_log_info(io->ocs, "[%s]" SCSI_IOFMT fmt, \
62 io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__)
63
64 #define scsi_io_trace(io, fmt, ...) \
65 do { \
66 if (OCS_LOG_ENABLE_SCSI_TRACE(io->ocs)) \
67 scsi_io_printf(io, fmt, ##__VA_ARGS__); \
68 } while (0)
69
70 #define scsi_log(ocs, fmt, ...) \
71 do { \
72 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) \
73 ocs_log_info(ocs, fmt, ##__VA_ARGS__); \
74 } while (0)
75
76 static int32_t ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg);
77 static int32_t ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
78 uint32_t ext, void *arg);
79
80 static void ocs_scsi_io_free_ovfl(ocs_io_t *io);
81 static uint32_t ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count);
82 static int ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info);
83 static ocs_scsi_io_status_e ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc);
84 static uint32_t ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[],
85 uint32_t addrlen_count, ocs_dif_t *dif, int is_crc);
86 static uint32_t ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif);
87 static uint32_t ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif);
88 static int32_t ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info,
89 ocs_hw_dif_info_t *hw_dif_info);
90 static int32_t ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio);
91 static int32_t ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io);
92 static void _ocs_scsi_io_free(void *arg);
93
94
95 /**
96 * @ingroup scsi_api_base
97 * @brief Returns a big-endian 32-bit value given a pointer.
98 *
99 * @param p Pointer to the 32-bit big-endian location.
100 *
101 * @return Returns the byte-swapped 32-bit value.
102 */
103
104 static inline uint32_t
ocs_fc_getbe32(void * p)105 ocs_fc_getbe32(void *p)
106 {
107 return ocs_be32toh(*((uint32_t*)p));
108 }
109
110 /**
111 * @ingroup scsi_api_base
112 * @brief Enable IO allocation.
113 *
114 * @par Description
115 * The SCSI and Transport IO allocation functions are enabled. If the allocation functions
116 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
117 * fail.
118 *
119 * @param node Pointer to node object.
120 *
121 * @return None.
122 */
123 void
ocs_scsi_io_alloc_enable(ocs_node_t * node)124 ocs_scsi_io_alloc_enable(ocs_node_t *node)
125 {
126 ocs_assert(node != NULL);
127 ocs_lock(&node->active_ios_lock);
128 node->io_alloc_enabled = TRUE;
129 ocs_unlock(&node->active_ios_lock);
130 }
131
132 /**
133 * @ingroup scsi_api_base
134 * @brief Disable IO allocation
135 *
136 * @par Description
137 * The SCSI and Transport IO allocation functions are disabled. If the allocation functions
138 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will
139 * fail.
140 *
141 * @param node Pointer to node object
142 *
143 * @return None.
144 */
145 void
ocs_scsi_io_alloc_disable(ocs_node_t * node)146 ocs_scsi_io_alloc_disable(ocs_node_t *node)
147 {
148 ocs_assert(node != NULL);
149 ocs_lock(&node->active_ios_lock);
150 node->io_alloc_enabled = FALSE;
151 ocs_unlock(&node->active_ios_lock);
152 }
153
154 /**
155 * @ingroup scsi_api_base
156 * @brief Allocate a SCSI IO context.
157 *
158 * @par Description
159 * A SCSI IO context is allocated and associated with a @c node. This function
160 * is called by an initiator-client when issuing SCSI commands to remote
161 * target devices. On completion, ocs_scsi_io_free() is called.
162 * @n @n
163 * The returned ocs_io_t structure has an element of type ocs_scsi_ini_io_t named
164 * "ini_io" that is declared and used by an initiator-client for private information.
165 *
166 * @param node Pointer to the associated node structure.
167 * @param role Role for IO (originator/responder).
168 *
169 * @return Returns the pointer to the IO context, or NULL.
170 *
171 */
172
173 ocs_io_t *
ocs_scsi_io_alloc(ocs_node_t * node,ocs_scsi_io_role_e role)174 ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role)
175 {
176 ocs_t *ocs;
177 ocs_xport_t *xport;
178 ocs_io_t *io;
179
180 ocs_assert(node, NULL);
181 ocs_assert(node->ocs, NULL);
182
183 ocs = node->ocs;
184 ocs_assert(ocs->xport, NULL);
185 xport = ocs->xport;
186
187 ocs_lock(&node->active_ios_lock);
188
189 if (!node->io_alloc_enabled) {
190 ocs_unlock(&node->active_ios_lock);
191 return NULL;
192 }
193
194 io = ocs_io_alloc(ocs);
195 if (io == NULL) {
196 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
197 ocs_unlock(&node->active_ios_lock);
198 return NULL;
199 }
200
201 /* initialize refcount */
202 ocs_ref_init(&io->ref, _ocs_scsi_io_free, io);
203
204 if (io->hio != NULL) {
205 ocs_log_err(node->ocs, "assertion failed: io->hio is not NULL\n");
206 ocs_unlock(&node->active_ios_lock);
207 return NULL;
208 }
209
210 /* set generic fields */
211 io->ocs = ocs;
212 io->node = node;
213
214 /* set type and name */
215 io->io_type = OCS_IO_TYPE_IO;
216 io->display_name = "scsi_io";
217
218 switch (role) {
219 case OCS_SCSI_IO_ROLE_ORIGINATOR:
220 io->cmd_ini = TRUE;
221 io->cmd_tgt = FALSE;
222 break;
223 case OCS_SCSI_IO_ROLE_RESPONDER:
224 io->cmd_ini = FALSE;
225 io->cmd_tgt = TRUE;
226 break;
227 }
228
229 /* Add to node's active_ios list */
230 ocs_list_add_tail(&node->active_ios, io);
231
232 ocs_unlock(&node->active_ios_lock);
233
234 return io;
235 }
236
237 /**
238 * @ingroup scsi_api_base
239 * @brief Free a SCSI IO context (internal).
240 *
241 * @par Description
242 * The IO context previously allocated using ocs_scsi_io_alloc()
243 * is freed. This is called from within the transport layer,
244 * when the reference count goes to zero.
245 *
246 * @param arg Pointer to the IO context.
247 *
248 * @return None.
249 */
250 static void
_ocs_scsi_io_free(void * arg)251 _ocs_scsi_io_free(void *arg)
252 {
253 ocs_io_t *io = (ocs_io_t *)arg;
254 ocs_t *ocs = io->ocs;
255 ocs_node_t *node = io->node;
256 int send_empty_event;
257
258 ocs_assert(io != NULL);
259
260 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
261
262 ocs_assert(ocs_io_busy(io));
263
264 ocs_lock(&node->active_ios_lock);
265 ocs_list_remove(&node->active_ios, io);
266 send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->active_ios);
267 ocs_unlock(&node->active_ios_lock);
268
269 if (send_empty_event) {
270 ocs_node_post_event(node, OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY, NULL);
271 }
272
273 io->node = NULL;
274 ocs_io_free(ocs, io);
275
276 }
277
278 /**
279 * @ingroup scsi_api_base
280 * @brief Free a SCSI IO context.
281 *
282 * @par Description
283 * The IO context previously allocated using ocs_scsi_io_alloc() is freed.
284 *
285 * @param io Pointer to the IO context.
286 *
287 * @return None.
288 */
289 void
ocs_scsi_io_free(ocs_io_t * io)290 ocs_scsi_io_free(ocs_io_t *io)
291 {
292 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
293 ocs_assert(ocs_ref_read_count(&io->ref) > 0);
294 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
295 }
296
297
298
299 static int32_t
300 ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
301 ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
302 ocs_scsi_dif_info_t *dif_info,
303 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
304 ocs_scsi_rsp_io_cb_t cb, void *arg);
305
306 /**
307 * @brief Target response completion callback.
308 *
309 * @par Description
310 * Function is called upon the completion of a target IO request.
311 *
312 * @param hio Pointer to the HW IO structure.
313 * @param rnode Remote node associated with the IO that is completing.
314 * @param length Length of the response payload.
315 * @param status Completion status.
316 * @param ext_status Extended completion status.
317 * @param app Application-specific data (generally a pointer to the IO context).
318 *
319 * @return None.
320 */
321
322 static void
ocs_target_io_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)323 ocs_target_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
324 int32_t status, uint32_t ext_status, void *app)
325 {
326 ocs_io_t *io = app;
327 ocs_t *ocs;
328 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
329 uint16_t additional_length;
330 uint8_t edir;
331 uint8_t tdpv;
332 ocs_hw_dif_info_t *dif_info = &io->hw_dif;
333 int is_crc;
334
335 ocs_assert(io);
336
337 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
338
339 ocs = io->ocs;
340 ocs_assert(ocs);
341
342 ocs_scsi_io_free_ovfl(io);
343
344 io->transferred += length;
345
346 /* Call target server completion */
347 if (io->scsi_tgt_cb) {
348 ocs_scsi_io_cb_t cb = io->scsi_tgt_cb;
349 uint32_t flags = 0;
350
351 /* Clear the callback before invoking the callback */
352 io->scsi_tgt_cb = NULL;
353
354 /* if status was good, and auto-good-response was set, then callback
355 * target-server with IO_CMPL_RSP_SENT, otherwise send IO_CMPL
356 */
357 if ((status == 0) && (io->auto_resp))
358 flags |= OCS_SCSI_IO_CMPL_RSP_SENT;
359 else
360 flags |= OCS_SCSI_IO_CMPL;
361
362 switch (status) {
363 case SLI4_FC_WCQE_STATUS_SUCCESS:
364 scsi_status = OCS_SCSI_STATUS_GOOD;
365 break;
366 case SLI4_FC_WCQE_STATUS_DI_ERROR:
367 if (ext_status & SLI4_FC_DI_ERROR_GE) {
368 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
369 } else if (ext_status & SLI4_FC_DI_ERROR_AE) {
370 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
371 } else if (ext_status & SLI4_FC_DI_ERROR_RE) {
372 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
373 } else {
374 additional_length = ((ext_status >> 16) & 0xFFFF);
375
376 /* Capture the EDIR and TDPV bits as 0 or 1 for easier printing. */
377 edir = !!(ext_status & SLI4_FC_DI_ERROR_EDIR);
378 tdpv = !!(ext_status & SLI4_FC_DI_ERROR_TDPV);
379
380 is_crc = ocs_scsi_dif_guard_is_crc(edir, dif_info);
381
382 if (edir == 0) {
383 /* For reads, we have everything in memory. Start checking from beginning. */
384 scsi_status = ocs_scsi_dif_check_unknown(io, 0, io->wire_len, is_crc);
385 } else {
386 /* For writes, use the additional length to determine where to look for the error.
387 * The additional_length field is set to 0 if it is not supported.
388 * The additional length field is valid if:
389 * . additional_length is not zero
390 * . Total Data Placed is valid
391 * . Error Direction is RX (1)
392 * . Operation is a pass thru (CRC or CKSUM on IN, and CRC or CHKSUM on OUT) (all pass-thru cases except raw)
393 */
394 if ((additional_length != 0) && (tdpv != 0) &&
395 (dif_info->dif == SLI4_DIF_PASS_THROUGH) && (dif_info->dif_oper != OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW) ) {
396 scsi_status = ocs_scsi_dif_check_unknown(io, length, additional_length, is_crc);
397 } else {
398 /* If we can't do additional checking, then fall-back to guard error */
399 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
400 }
401 }
402 }
403 break;
404 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
405 switch (ext_status) {
406 case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET:
407 case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED:
408 scsi_status = OCS_SCSI_STATUS_ABORTED;
409 break;
410 case SLI4_FC_LOCAL_REJECT_INVALID_RPI:
411 scsi_status = OCS_SCSI_STATUS_NEXUS_LOST;
412 break;
413 case SLI4_FC_LOCAL_REJECT_NO_XRI:
414 scsi_status = OCS_SCSI_STATUS_NO_IO;
415 break;
416 default:
417 /* TODO: we have seen 0x0d (TX_DMA_FAILED error) */
418 scsi_status = OCS_SCSI_STATUS_ERROR;
419 break;
420 }
421 break;
422
423 case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT:
424 /* target IO timed out */
425 scsi_status = OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED;
426 break;
427
428 case SLI4_FC_WCQE_STATUS_SHUTDOWN:
429 /* Target IO cancelled by HW */
430 scsi_status = OCS_SCSI_STATUS_SHUTDOWN;
431 break;
432
433 default:
434 scsi_status = OCS_SCSI_STATUS_ERROR;
435 break;
436 }
437
438 cb(io, scsi_status, flags, io->scsi_tgt_cb_arg);
439
440 }
441 ocs_scsi_check_pending(ocs);
442 }
443
444 /**
445 * @brief Determine if an IO is using CRC for DIF guard format.
446 *
447 * @param direction IO direction: 1 for write, 0 for read.
448 * @param dif_info Pointer to HW DIF info data.
449 *
450 * @return Returns TRUE if using CRC, FALSE if not.
451 */
452 static int
ocs_scsi_dif_guard_is_crc(uint8_t direction,ocs_hw_dif_info_t * dif_info)453 ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info)
454 {
455 int is_crc;
456
457 if (direction) {
458 /* For writes, check if operation is "OUT_CRC" or not */
459 switch(dif_info->dif_oper) {
460 case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC:
461 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
462 case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC:
463 is_crc = TRUE;
464 break;
465 default:
466 is_crc = FALSE;
467 break;
468 }
469 } else {
470 /* For reads, check if operation is "IN_CRC" or not */
471 switch(dif_info->dif_oper) {
472 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF:
473 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC:
474 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM:
475 is_crc = TRUE;
476 break;
477 default:
478 is_crc = FALSE;
479 break;
480 }
481 }
482
483 return is_crc;
484 }
485
486 /**
487 * @brief Check a block and DIF data, computing the appropriate SCSI status
488 *
489 * @par Description
490 * This function is used to check blocks and DIF when given an unknown DIF
491 * status using the following logic:
492 *
493 * Given the address of the last good block, and a length of bytes that includes
494 * the block with the DIF error, find the bad block. If a block is found with an
495 * app_tag or ref_tag error, then return the appropriate error. No block is expected
496 * to have a block guard error since hardware "fixes" the crc. So if no block in the
497 * range of blocks has an error, then it is presumed to be a BLOCK GUARD error.
498 *
499 * @param io Pointer to the IO object.
500 * @param length Length of bytes covering the good blocks.
501 * @param check_length Length of bytes that covers the bad block.
502 * @param is_crc True if guard is using CRC format.
503 *
504 * @return Returns SCSI status.
505 */
506
507 static ocs_scsi_io_status_e
ocs_scsi_dif_check_unknown(ocs_io_t * io,uint32_t length,uint32_t check_length,int is_crc)508 ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc)
509 {
510 uint32_t i;
511 ocs_t *ocs = io->ocs;
512 ocs_hw_dif_info_t *dif_info = &io->hw_dif;
513 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
514 uint32_t blocksize; /* data block size */
515 uint64_t first_check_block; /* first block following total data placed */
516 uint64_t last_check_block; /* last block to check */
517 uint32_t check_count; /* count of blocks to check */
518 ocs_scsi_vaddr_len_t addrlen[4]; /* address-length pairs returned from target */
519 int32_t addrlen_count; /* count of address-length pairs */
520 ocs_dif_t *dif; /* pointer to DIF block returned from target */
521 ocs_scsi_dif_info_t scsi_dif_info = io->scsi_dif_info;
522
523 blocksize = ocs_hw_dif_mem_blocksize(&io->hw_dif, TRUE);
524 first_check_block = length / blocksize;
525 last_check_block = ((length + check_length) / blocksize);
526 check_count = last_check_block - first_check_block;
527
528 ocs_log_debug(ocs, "blocksize %d first check_block %" PRId64 " last_check_block %" PRId64 " check_count %d\n",
529 blocksize, first_check_block, last_check_block, check_count);
530
531 for (i = first_check_block; i < last_check_block; i++) {
532 addrlen_count = ocs_scsi_get_block_vaddr(io, (scsi_dif_info.lba + i), addrlen, ARRAY_SIZE(addrlen), (void**) &dif);
533 if (addrlen_count < 0) {
534 ocs_log_test(ocs, "ocs_scsi_get_block_vaddr() failed: %d\n", addrlen_count);
535 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
536 break;
537 }
538
539 if (! ocs_scsi_dif_check_guard(dif_info, addrlen, addrlen_count, dif, is_crc)) {
540 ocs_log_debug(ocs, "block guard check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
541 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
542 break;
543 }
544 if (! ocs_scsi_dif_check_app_tag(ocs, dif_info, scsi_dif_info.app_tag, dif)) {
545 ocs_log_debug(ocs, "app tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
546 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
547 break;
548 }
549 if (! ocs_scsi_dif_check_ref_tag(ocs, dif_info, (scsi_dif_info.ref_tag + i), dif)) {
550 ocs_log_debug(ocs, "ref tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i);
551 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
552 break;
553 }
554
555 }
556 return scsi_status;
557 }
558
559 /**
560 * @brief Check the block guard of block data
561 *
562 * @par Description
563 * Using the dif_info for the transfer, check the block guard value.
564 *
565 * @param dif_info Pointer to HW DIF info data.
566 * @param addrlen Array of address length pairs.
567 * @param addrlen_count Number of entries in the addrlen[] array.
568 * @param dif Pointer to the DIF data block being checked.
569 * @param is_crc True if guard is using CRC format.
570 *
571 * @return Returns TRUE if block guard check is ok.
572 */
573 static uint32_t
ocs_scsi_dif_check_guard(ocs_hw_dif_info_t * dif_info,ocs_scsi_vaddr_len_t addrlen[],uint32_t addrlen_count,ocs_dif_t * dif,int is_crc)574 ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count,
575 ocs_dif_t *dif, int is_crc)
576 {
577 uint16_t crc = dif_info->dif_seed;
578 uint32_t i;
579 uint16_t checksum;
580
581 if ((dif == NULL) || !dif_info->check_guard) {
582 return TRUE;
583 }
584
585 if (is_crc) {
586 for (i = 0; i < addrlen_count; i++) {
587 crc = ocs_scsi_dif_calc_crc(addrlen[i].vaddr, addrlen[i].length, crc);
588 }
589 return (crc == ocs_be16toh(dif->crc));
590 } else {
591 checksum = ocs_scsi_dif_calc_checksum(addrlen, addrlen_count);
592
593 return (checksum == dif->crc);
594 }
595 }
596
597 /**
598 * @brief Check the app tag of dif data
599 *
600 * @par Description
601 * Using the dif_info for the transfer, check the app tag.
602 *
603 * @param ocs Pointer to the ocs structure for logging.
604 * @param dif_info Pointer to HW DIF info data.
605 * @param exp_app_tag The value the app tag is expected to be.
606 * @param dif Pointer to the DIF data block being checked.
607 *
608 * @return Returns TRUE if app tag check is ok.
609 */
610 static uint32_t
ocs_scsi_dif_check_app_tag(ocs_t * ocs,ocs_hw_dif_info_t * dif_info,uint16_t exp_app_tag,ocs_dif_t * dif)611 ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif)
612 {
613 if ((dif == NULL) || !dif_info->check_app_tag) {
614 return TRUE;
615 }
616
617 ocs_log_debug(ocs, "expected app tag 0x%x, actual 0x%x\n",
618 exp_app_tag, ocs_be16toh(dif->app_tag));
619
620 return (exp_app_tag == ocs_be16toh(dif->app_tag));
621 }
622
623 /**
624 * @brief Check the ref tag of dif data
625 *
626 * @par Description
627 * Using the dif_info for the transfer, check the app tag.
628 *
629 * @param ocs Pointer to the ocs structure for logging.
630 * @param dif_info Pointer to HW DIF info data.
631 * @param exp_ref_tag The value the ref tag is expected to be.
632 * @param dif Pointer to the DIF data block being checked.
633 *
634 * @return Returns TRUE if ref tag check is ok.
635 */
636 static uint32_t
ocs_scsi_dif_check_ref_tag(ocs_t * ocs,ocs_hw_dif_info_t * dif_info,uint32_t exp_ref_tag,ocs_dif_t * dif)637 ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif)
638 {
639 if ((dif == NULL) || !dif_info->check_ref_tag) {
640 return TRUE;
641 }
642
643 if (exp_ref_tag != ocs_be32toh(dif->ref_tag)) {
644 ocs_log_debug(ocs, "expected ref tag 0x%x, actual 0x%x\n",
645 exp_ref_tag, ocs_be32toh(dif->ref_tag));
646 return FALSE;
647 } else {
648 return TRUE;
649 }
650 }
651
652 /**
653 * @brief Return count of SGE's required for request
654 *
655 * @par Description
656 * An accurate count of SGEs is computed and returned.
657 *
658 * @param hw_dif Pointer to HW dif information.
659 * @param sgl Pointer to SGL from back end.
660 * @param sgl_count Count of SGEs in SGL.
661 *
662 * @return Count of SGEs.
663 */
664 static uint32_t
ocs_scsi_count_sgls(ocs_hw_dif_info_t * hw_dif,ocs_scsi_sgl_t * sgl,uint32_t sgl_count)665 ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count)
666 {
667 uint32_t count = 0;
668 uint32_t i;
669
670 /* Convert DIF Information */
671 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
672
673 /* If we're not DIF separate, then emit a seed SGE */
674 if (!hw_dif->dif_separate) {
675 count++;
676 }
677
678 for (i = 0; i < sgl_count; i++) {
679 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
680 if (hw_dif->dif_separate) {
681 count += 2;
682 }
683
684 count++;
685 }
686 } else {
687 count = sgl_count;
688 }
689 return count;
690 }
691
692 static int32_t
ocs_scsi_build_sgls(ocs_hw_t * hw,ocs_hw_io_t * hio,ocs_hw_dif_info_t * hw_dif,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,ocs_hw_io_type_e type)693 ocs_scsi_build_sgls(ocs_hw_t *hw, ocs_hw_io_t *hio, ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count, ocs_hw_io_type_e type)
694 {
695 int32_t rc;
696 uint32_t i;
697 ocs_t *ocs = hw->os;
698 uint32_t blocksize = 0;
699 uint32_t blockcount;
700
701 ocs_assert(hio, -1);
702
703 /* Initialize HW SGL */
704 rc = ocs_hw_io_init_sges(hw, hio, type);
705 if (rc) {
706 ocs_log_err(ocs, "ocs_hw_io_init_sges failed: %d\n", rc);
707 return -1;
708 }
709
710 /* Convert DIF Information */
711 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) {
712
713 /* If we're not DIF separate, then emit a seed SGE */
714 if (!hw_dif->dif_separate) {
715 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
716 if (rc) {
717 return rc;
718 }
719 }
720
721 /* if we are doing DIF separate, then figure out the block size so that we
722 * can update the ref tag in the DIF seed SGE. Also verify that the
723 * the sgl lengths are all multiples of the blocksize
724 */
725 if (hw_dif->dif_separate) {
726 switch(hw_dif->blk_size) {
727 case OCS_HW_DIF_BK_SIZE_512: blocksize = 512; break;
728 case OCS_HW_DIF_BK_SIZE_1024: blocksize = 1024; break;
729 case OCS_HW_DIF_BK_SIZE_2048: blocksize = 2048; break;
730 case OCS_HW_DIF_BK_SIZE_4096: blocksize = 4096; break;
731 case OCS_HW_DIF_BK_SIZE_520: blocksize = 520; break;
732 case OCS_HW_DIF_BK_SIZE_4104: blocksize = 4104; break;
733 default:
734 ocs_log_test(hw->os, "Inavlid hw_dif blocksize %d\n", hw_dif->blk_size);
735 return -1;
736 }
737 for (i = 0; i < sgl_count; i++) {
738 if ((sgl[i].len % blocksize) != 0) {
739 ocs_log_test(hw->os, "sgl[%d] len of %ld is not multiple of blocksize\n",
740 i, sgl[i].len);
741 return -1;
742 }
743 }
744 }
745
746 for (i = 0; i < sgl_count; i++) {
747 ocs_assert(sgl[i].addr, -1);
748 ocs_assert(sgl[i].len, -1);
749
750 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */
751 if (hw_dif->dif_separate) {
752 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif);
753 if (rc) {
754 return rc;
755 }
756 rc = ocs_hw_io_add_dif_sge(hw, hio, sgl[i].dif_addr);
757 if (rc) {
758 return rc;
759 }
760 /* Update the ref_tag for the next DIF seed SGE */
761 blockcount = sgl[i].len / blocksize;
762 if (hw_dif->dif_oper == OCS_HW_DIF_OPER_INSERT) {
763 hw_dif->ref_tag_repl += blockcount;
764 } else {
765 hw_dif->ref_tag_cmp += blockcount;
766 }
767 }
768
769 /* Add data SGE */
770 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
771 if (rc) {
772 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
773 sgl_count, rc);
774 return rc;
775 }
776 }
777 } else {
778 for (i = 0; i < sgl_count; i++) {
779 ocs_assert(sgl[i].addr, -1);
780 ocs_assert(sgl[i].len, -1);
781
782 /* Add data SGE */
783 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len);
784 if (rc) {
785 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n",
786 sgl_count, rc);
787 return rc;
788 }
789
790 }
791 }
792 return 0;
793 }
794
795 /**
796 * @ingroup scsi_api_base
797 * @brief Convert SCSI API T10 DIF information into the FC HW format.
798 *
799 * @param ocs Pointer to the ocs structure for logging.
800 * @param scsi_dif_info Pointer to the SCSI API T10 DIF fields.
801 * @param hw_dif_info Pointer to the FC HW API T10 DIF fields.
802 *
803 * @return Returns 0 on success, or a negative error code value on failure.
804 */
805
806 static int32_t
ocs_scsi_convert_dif_info(ocs_t * ocs,ocs_scsi_dif_info_t * scsi_dif_info,ocs_hw_dif_info_t * hw_dif_info)807 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, ocs_hw_dif_info_t *hw_dif_info)
808 {
809 uint32_t dif_seed;
810 ocs_memset(hw_dif_info, 0, sizeof(ocs_hw_dif_info_t));
811
812 if (scsi_dif_info == NULL) {
813 hw_dif_info->dif_oper = OCS_HW_DIF_OPER_DISABLED;
814 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_NA;
815 return 0;
816 }
817
818 /* Convert the DIF operation */
819 switch(scsi_dif_info->dif_oper) {
820 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC:
821 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC;
822 hw_dif_info->dif = SLI4_DIF_INSERT;
823 break;
824 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF:
825 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF;
826 hw_dif_info->dif = SLI4_DIF_STRIP;
827 break;
828 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM:
829 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM;
830 hw_dif_info->dif = SLI4_DIF_INSERT;
831 break;
832 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF:
833 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF;
834 hw_dif_info->dif = SLI4_DIF_STRIP;
835 break;
836 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC:
837 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC;
838 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
839 break;
840 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM:
841 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM;
842 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
843 break;
844 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM:
845 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM;
846 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
847 break;
848 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC:
849 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC;
850 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
851 break;
852 case OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW:
853 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW;
854 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH;
855 break;
856 default:
857 ocs_log_test(ocs, "unhandled SCSI DIF operation %d\n",
858 scsi_dif_info->dif_oper);
859 return -1;
860 }
861
862 switch(scsi_dif_info->blk_size) {
863 case OCS_SCSI_DIF_BK_SIZE_512:
864 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_512;
865 break;
866 case OCS_SCSI_DIF_BK_SIZE_1024:
867 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_1024;
868 break;
869 case OCS_SCSI_DIF_BK_SIZE_2048:
870 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_2048;
871 break;
872 case OCS_SCSI_DIF_BK_SIZE_4096:
873 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4096;
874 break;
875 case OCS_SCSI_DIF_BK_SIZE_520:
876 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_520;
877 break;
878 case OCS_SCSI_DIF_BK_SIZE_4104:
879 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4104;
880 break;
881 default:
882 ocs_log_test(ocs, "unhandled SCSI DIF block size %d\n",
883 scsi_dif_info->blk_size);
884 return -1;
885 }
886
887 /* If the operation is an INSERT the tags provided are the ones that should be
888 * inserted, otherwise they're the ones to be checked against. */
889 if (hw_dif_info->dif == SLI4_DIF_INSERT ) {
890 hw_dif_info->ref_tag_repl = scsi_dif_info->ref_tag;
891 hw_dif_info->app_tag_repl = scsi_dif_info->app_tag;
892 } else {
893 hw_dif_info->ref_tag_cmp = scsi_dif_info->ref_tag;
894 hw_dif_info->app_tag_cmp = scsi_dif_info->app_tag;
895 }
896
897 hw_dif_info->check_ref_tag = scsi_dif_info->check_ref_tag;
898 hw_dif_info->check_app_tag = scsi_dif_info->check_app_tag;
899 hw_dif_info->check_guard = scsi_dif_info->check_guard;
900 hw_dif_info->auto_incr_ref_tag = 1;
901 hw_dif_info->dif_separate = scsi_dif_info->dif_separate;
902 hw_dif_info->disable_app_ffff = scsi_dif_info->disable_app_ffff;
903 hw_dif_info->disable_app_ref_ffff = scsi_dif_info->disable_app_ref_ffff;
904
905 ocs_hw_get(&ocs->hw, OCS_HW_DIF_SEED, &dif_seed);
906 hw_dif_info->dif_seed = dif_seed;
907
908 return 0;
909 }
910
911 /**
912 * @ingroup scsi_api_base
913 * @brief This function logs the SGLs for an IO.
914 *
915 * @param io Pointer to the IO context.
916 */
ocs_log_sgl(ocs_io_t * io)917 static void ocs_log_sgl(ocs_io_t *io)
918 {
919 ocs_hw_io_t *hio = io->hio;
920 sli4_sge_t *data = NULL;
921 uint32_t *dword = NULL;
922 uint32_t i;
923 uint32_t n_sge;
924
925 scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n",
926 ocs_addr32_hi(hio->def_sgl.phys),
927 ocs_addr32_lo(hio->def_sgl.phys));
928 n_sge = (hio->sgl == &hio->def_sgl ? hio->n_sge : hio->def_sgl_count);
929 for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) {
930 dword = (uint32_t*)data;
931
932 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
933 i, dword[0], dword[1], dword[2], dword[3]);
934
935 if (dword[2] & (1U << 31)) {
936 break;
937 }
938 }
939
940 if (hio->ovfl_sgl != NULL &&
941 hio->sgl == hio->ovfl_sgl) {
942 scsi_io_trace(io, "Overflow at 0x%x 0x%08x\n",
943 ocs_addr32_hi(hio->ovfl_sgl->phys),
944 ocs_addr32_lo(hio->ovfl_sgl->phys));
945 for (i = 0, data = hio->ovfl_sgl->virt; i < hio->n_sge; i++, data++) {
946 dword = (uint32_t*)data;
947
948 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
949 i, dword[0], dword[1], dword[2], dword[3]);
950 if (dword[2] & (1U << 31)) {
951 break;
952 }
953 }
954 }
955
956 }
957
958
959 /**
960 * @brief Check pending error asynchronous callback function.
961 *
962 * @par Description
963 * Invoke the HW callback function for a given IO. This function is called
964 * from the NOP mailbox completion context.
965 *
966 * @param hw Pointer to HW object.
967 * @param status Completion status.
968 * @param mqe Mailbox completion queue entry.
969 * @param arg General purpose argument.
970 *
971 * @return Returns 0.
972 */
973 static int32_t
ocs_scsi_check_pending_async_cb(ocs_hw_t * hw,int32_t status,uint8_t * mqe,void * arg)974 ocs_scsi_check_pending_async_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
975 {
976 ocs_io_t *io = arg;
977
978 if (io != NULL) {
979 if (io->hw_cb != NULL) {
980 ocs_hw_done_t cb = io->hw_cb;
981
982 io->hw_cb = NULL;
983 cb(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io);
984 }
985 }
986 return 0;
987 }
988
989 /**
990 * @brief Check for pending IOs to dispatch.
991 *
992 * @par Description
993 * If there are IOs on the pending list, and a HW IO is available, then
994 * dispatch the IOs.
995 *
996 * @param ocs Pointer to the OCS structure.
997 *
998 * @return None.
999 */
1000
1001 void
ocs_scsi_check_pending(ocs_t * ocs)1002 ocs_scsi_check_pending(ocs_t *ocs)
1003 {
1004 ocs_xport_t *xport = ocs->xport;
1005 ocs_io_t *io;
1006 ocs_hw_io_t *hio;
1007 int32_t status;
1008 int count = 0;
1009 int dispatch;
1010
1011 /* Guard against recursion */
1012 if (ocs_atomic_add_return(&xport->io_pending_recursing, 1)) {
1013 /* This function is already running. Decrement and return. */
1014 ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
1015 return;
1016 }
1017
1018 do {
1019 ocs_lock(&xport->io_pending_lock);
1020 status = 0;
1021 hio = NULL;
1022 io = ocs_list_remove_head(&xport->io_pending_list);
1023 if (io != NULL) {
1024 if (io->io_type == OCS_IO_TYPE_ABORT) {
1025 hio = NULL;
1026 } else {
1027 hio = ocs_hw_io_alloc(&ocs->hw);
1028 if (hio == NULL) {
1029 /*
1030 * No HW IO available.
1031 * Put IO back on the front of pending list
1032 */
1033 ocs_list_add_head(&xport->io_pending_list, io);
1034 io = NULL;
1035 } else {
1036 hio->eq = io->hw_priv;
1037 }
1038 }
1039 }
1040 /* Must drop the lock before dispatching the IO */
1041 ocs_unlock(&xport->io_pending_lock);
1042
1043 if (io != NULL) {
1044 count++;
1045
1046 /*
1047 * We pulled an IO off the pending list,
1048 * and either got an HW IO or don't need one
1049 */
1050 ocs_atomic_sub_return(&xport->io_pending_count, 1);
1051 if (hio == NULL) {
1052 status = ocs_scsi_io_dispatch_no_hw_io(io);
1053 } else {
1054 status = ocs_scsi_io_dispatch_hw_io(io, hio);
1055 }
1056 if (status) {
1057 /*
1058 * Invoke the HW callback, but do so in the separate execution context,
1059 * provided by the NOP mailbox completion processing context by using
1060 * ocs_hw_async_call()
1061 */
1062 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
1063 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
1064 }
1065 }
1066 }
1067 } while (io != NULL);
1068
1069
1070 /*
1071 * If nothing was removed from the list,
1072 * we might be in a case where we need to abort an
1073 * active IO and the abort is on the pending list.
1074 * Look for an abort we can dispatch.
1075 */
1076 if (count == 0 ) {
1077 dispatch = 0;
1078
1079 ocs_lock(&xport->io_pending_lock);
1080 ocs_list_foreach(&xport->io_pending_list, io) {
1081 if (io->io_type == OCS_IO_TYPE_ABORT) {
1082 if (io->io_to_abort->hio != NULL) {
1083 /* This IO has a HW IO, so it is active. Dispatch the abort. */
1084 dispatch = 1;
1085 } else {
1086 /* Leave this abort on the pending list and keep looking */
1087 dispatch = 0;
1088 }
1089 }
1090 if (dispatch) {
1091 ocs_list_remove(&xport->io_pending_list, io);
1092 ocs_atomic_sub_return(&xport->io_pending_count, 1);
1093 break;
1094 }
1095 }
1096 ocs_unlock(&xport->io_pending_lock);
1097
1098 if (dispatch) {
1099 status = ocs_scsi_io_dispatch_no_hw_io(io);
1100 if (status) {
1101 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) {
1102 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n");
1103 }
1104 }
1105 }
1106 }
1107
1108 ocs_atomic_sub_return(&xport->io_pending_recursing, 1);
1109 return;
1110 }
1111
1112 /**
1113 * @brief Attempt to dispatch a non-abort IO
1114 *
1115 * @par Description
1116 * An IO is dispatched:
1117 * - if the pending list is not empty, add IO to pending list
1118 * and call a function to process the pending list.
1119 * - if pending list is empty, try to allocate a HW IO. If none
1120 * is available, place this IO at the tail of the pending IO
1121 * list.
1122 * - if HW IO is available, attach this IO to the HW IO and
1123 * submit it.
1124 *
1125 * @param io Pointer to IO structure.
1126 * @param cb Callback function.
1127 *
1128 * @return Returns 0 on success, a negative error code value on failure.
1129 */
1130
1131 int32_t
ocs_scsi_io_dispatch(ocs_io_t * io,void * cb)1132 ocs_scsi_io_dispatch(ocs_io_t *io, void *cb)
1133 {
1134 ocs_hw_io_t *hio;
1135 ocs_t *ocs = io->ocs;
1136 ocs_xport_t *xport = ocs->xport;
1137
1138 ocs_assert(io->cmd_tgt || io->cmd_ini, -1);
1139 ocs_assert((io->io_type != OCS_IO_TYPE_ABORT), -1);
1140 io->hw_cb = cb;
1141
1142 /*
1143 * if this IO already has a HW IO, then this is either not the first phase of
1144 * the IO. Send it to the HW.
1145 */
1146 if (io->hio != NULL) {
1147 return ocs_scsi_io_dispatch_hw_io(io, io->hio);
1148 }
1149
1150 /*
1151 * We don't already have a HW IO associated with the IO. First check
1152 * the pending list. If not empty, add IO to the tail and process the
1153 * pending list.
1154 */
1155 ocs_lock(&xport->io_pending_lock);
1156 if (!ocs_list_empty(&xport->io_pending_list)) {
1157 /*
1158 * If this is a low latency request, the put at the front of the IO pending
1159 * queue, otherwise put it at the end of the queue.
1160 */
1161 if (io->low_latency) {
1162 ocs_list_add_head(&xport->io_pending_list, io);
1163 } else {
1164 ocs_list_add_tail(&xport->io_pending_list, io);
1165 }
1166 ocs_unlock(&xport->io_pending_lock);
1167 ocs_atomic_add_return(&xport->io_pending_count, 1);
1168 ocs_atomic_add_return(&xport->io_total_pending, 1);
1169
1170 /* process pending list */
1171 ocs_scsi_check_pending(ocs);
1172 return 0;
1173 }
1174 ocs_unlock(&xport->io_pending_lock);
1175
1176 /*
1177 * We don't have a HW IO associated with the IO and there's nothing
1178 * on the pending list. Attempt to allocate a HW IO and dispatch it.
1179 */
1180 hio = ocs_hw_io_alloc(&io->ocs->hw);
1181 if (hio == NULL) {
1182
1183 /* Couldn't get a HW IO. Save this IO on the pending list */
1184 ocs_lock(&xport->io_pending_lock);
1185 ocs_list_add_tail(&xport->io_pending_list, io);
1186 ocs_unlock(&xport->io_pending_lock);
1187
1188 ocs_atomic_add_return(&xport->io_total_pending, 1);
1189 ocs_atomic_add_return(&xport->io_pending_count, 1);
1190 return 0;
1191 }
1192
1193 /* We successfully allocated a HW IO; dispatch to HW */
1194 return ocs_scsi_io_dispatch_hw_io(io, hio);
1195 }
1196
1197 /**
1198 * @brief Attempt to dispatch an Abort IO.
1199 *
1200 * @par Description
1201 * An Abort IO is dispatched:
1202 * - if the pending list is not empty, add IO to pending list
1203 * and call a function to process the pending list.
1204 * - if pending list is empty, send abort to the HW.
1205 *
1206 * @param io Pointer to IO structure.
1207 * @param cb Callback function.
1208 *
1209 * @return Returns 0 on success, a negative error code value on failure.
1210 */
1211
1212 int32_t
ocs_scsi_io_dispatch_abort(ocs_io_t * io,void * cb)1213 ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb)
1214 {
1215 ocs_t *ocs = io->ocs;
1216 ocs_xport_t *xport = ocs->xport;
1217
1218 ocs_assert((io->io_type == OCS_IO_TYPE_ABORT), -1);
1219 io->hw_cb = cb;
1220
1221 /*
1222 * For aborts, we don't need a HW IO, but we still want to pass through
1223 * the pending list to preserve ordering. Thus, if the pending list is
1224 * not empty, add this abort to the pending list and process the pending list.
1225 */
1226 ocs_lock(&xport->io_pending_lock);
1227 if (!ocs_list_empty(&xport->io_pending_list)) {
1228 ocs_list_add_tail(&xport->io_pending_list, io);
1229 ocs_unlock(&xport->io_pending_lock);
1230 ocs_atomic_add_return(&xport->io_pending_count, 1);
1231 ocs_atomic_add_return(&xport->io_total_pending, 1);
1232
1233 /* process pending list */
1234 ocs_scsi_check_pending(ocs);
1235 return 0;
1236 }
1237 ocs_unlock(&xport->io_pending_lock);
1238
1239 /* nothing on pending list, dispatch abort */
1240 return ocs_scsi_io_dispatch_no_hw_io(io);
1241
1242 }
1243
1244 /**
1245 * @brief Dispatch IO
1246 *
1247 * @par Description
1248 * An IO and its associated HW IO is dispatched to the HW.
1249 *
1250 * @param io Pointer to IO structure.
1251 * @param hio Pointer to HW IO structure from which IO will be
1252 * dispatched.
1253 *
1254 * @return Returns 0 on success, a negative error code value on failure.
1255 */
1256
1257 static int32_t
ocs_scsi_io_dispatch_hw_io(ocs_io_t * io,ocs_hw_io_t * hio)1258 ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio)
1259 {
1260 int32_t rc;
1261 ocs_t *ocs = io->ocs;
1262
1263 /* Got a HW IO; update ini/tgt_task_tag with HW IO info and dispatch */
1264 io->hio = hio;
1265 if (io->cmd_tgt) {
1266 io->tgt_task_tag = hio->indicator;
1267 } else if (io->cmd_ini) {
1268 io->init_task_tag = hio->indicator;
1269 }
1270 io->hw_tag = hio->reqtag;
1271
1272 hio->eq = io->hw_priv;
1273
1274 /* Copy WQ steering */
1275 switch(io->wq_steering) {
1276 case OCS_SCSI_WQ_STEERING_CLASS >> OCS_SCSI_WQ_STEERING_SHIFT:
1277 hio->wq_steering = OCS_HW_WQ_STEERING_CLASS;
1278 break;
1279 case OCS_SCSI_WQ_STEERING_REQUEST >> OCS_SCSI_WQ_STEERING_SHIFT:
1280 hio->wq_steering = OCS_HW_WQ_STEERING_REQUEST;
1281 break;
1282 case OCS_SCSI_WQ_STEERING_CPU >> OCS_SCSI_WQ_STEERING_SHIFT:
1283 hio->wq_steering = OCS_HW_WQ_STEERING_CPU;
1284 break;
1285 }
1286
1287
1288 switch (io->io_type) {
1289 case OCS_IO_TYPE_IO: {
1290 uint32_t max_sgl;
1291 uint32_t total_count;
1292 uint32_t host_allocated;
1293
1294 ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl);
1295 ocs_hw_get(&ocs->hw, OCS_HW_SGL_CHAINING_HOST_ALLOCATED, &host_allocated);
1296
1297 /*
1298 * If the requested SGL is larger than the default size, then we can allocate
1299 * an overflow SGL.
1300 */
1301 total_count = ocs_scsi_count_sgls(&io->hw_dif, io->sgl, io->sgl_count);
1302
1303 /*
1304 * Lancer requires us to allocate the chained memory area, but
1305 * Skyhawk must use the SGL list associated with another XRI.
1306 */
1307 if (host_allocated && total_count > max_sgl) {
1308 /* Compute count needed, the number extra plus 1 for the link sge */
1309 uint32_t count = total_count - max_sgl + 1;
1310 rc = ocs_dma_alloc(ocs, &io->ovfl_sgl, count*sizeof(sli4_sge_t), 64);
1311 if (rc) {
1312 ocs_log_err(ocs, "ocs_dma_alloc overflow sgl failed\n");
1313 break;
1314 }
1315 rc = ocs_hw_io_register_sgl(&ocs->hw, io->hio, &io->ovfl_sgl, count);
1316 if (rc) {
1317 ocs_scsi_io_free_ovfl(io);
1318 ocs_log_err(ocs, "ocs_hw_io_register_sgl() failed\n");
1319 break;
1320 }
1321 /* EVT: update chained_io_count */
1322 io->node->chained_io_count++;
1323 }
1324
1325 rc = ocs_scsi_build_sgls(&ocs->hw, io->hio, &io->hw_dif, io->sgl, io->sgl_count, io->hio_type);
1326 if (rc) {
1327 ocs_scsi_io_free_ovfl(io);
1328 break;
1329 }
1330
1331 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
1332 ocs_log_sgl(io);
1333 }
1334
1335 if (io->app_id) {
1336 io->iparam.fcp_tgt.app_id = io->app_id;
1337 }
1338
1339 rc = ocs_hw_io_send(&io->ocs->hw, io->hio_type, io->hio, io->wire_len, &io->iparam, &io->node->rnode,
1340 io->hw_cb, io);
1341 break;
1342 }
1343 case OCS_IO_TYPE_ELS:
1344 case OCS_IO_TYPE_CT: {
1345 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1346 &io->els_req, io->wire_len,
1347 &io->els_rsp, &io->node->rnode, &io->iparam,
1348 io->hw_cb, io);
1349 break;
1350 }
1351 case OCS_IO_TYPE_CT_RESP: {
1352 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1353 &io->els_rsp, io->wire_len,
1354 NULL, &io->node->rnode, &io->iparam,
1355 io->hw_cb, io);
1356 break;
1357 }
1358 case OCS_IO_TYPE_BLS_RESP: {
1359 /* no need to update tgt_task_tag for BLS response since the RX_ID
1360 * will be specified by the payload, not the XRI */
1361 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio,
1362 NULL, 0, NULL, &io->node->rnode, &io->iparam, io->hw_cb, io);
1363 break;
1364 }
1365 default:
1366 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
1367 rc = -1;
1368 break;
1369 }
1370 return rc;
1371 }
1372
1373 /**
1374 * @brief Dispatch IO
1375 *
1376 * @par Description
1377 * An IO that does require a HW IO is dispatched to the HW.
1378 *
1379 * @param io Pointer to IO structure.
1380 *
1381 * @return Returns 0 on success, or a negative error code value on failure.
1382 */
1383
1384 static int32_t
ocs_scsi_io_dispatch_no_hw_io(ocs_io_t * io)1385 ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io)
1386 {
1387 int32_t rc;
1388
1389 switch (io->io_type) {
1390 case OCS_IO_TYPE_ABORT: {
1391 ocs_hw_io_t *hio_to_abort = NULL;
1392 ocs_assert(io->io_to_abort, -1);
1393 hio_to_abort = io->io_to_abort->hio;
1394
1395 if (hio_to_abort == NULL) {
1396 /*
1397 * If "IO to abort" does not have an associated HW IO, immediately
1398 * make callback with success. The command must have been sent to
1399 * the backend, but the data phase has not yet started, so we don't
1400 * have a HW IO.
1401 *
1402 * Note: since the backend shims should be taking a reference
1403 * on io_to_abort, it should not be possible to have been completed
1404 * and freed by the backend before the abort got here.
1405 */
1406 scsi_io_printf(io, "IO: " SCSI_IOFMT " not active\n",
1407 SCSI_IOFMT_ARGS(io->io_to_abort));
1408 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_SUCCESS, 0, io);
1409 rc = 0;
1410 } else {
1411 /* HW IO is valid, abort it */
1412 scsi_io_printf(io, "aborting " SCSI_IOFMT "\n", SCSI_IOFMT_ARGS(io->io_to_abort));
1413 rc = ocs_hw_io_abort(&io->ocs->hw, hio_to_abort, io->send_abts,
1414 io->hw_cb, io);
1415 if (rc) {
1416 int status = SLI4_FC_WCQE_STATUS_SUCCESS;
1417 if ((rc != OCS_HW_RTN_IO_NOT_ACTIVE) &&
1418 (rc != OCS_HW_RTN_IO_ABORT_IN_PROGRESS)) {
1419 status = -1;
1420 scsi_io_printf(io, "Failed to abort IO: " SCSI_IOFMT " status=%d\n",
1421 SCSI_IOFMT_ARGS(io->io_to_abort), rc);
1422 }
1423 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, status, 0, io);
1424 rc = 0;
1425 }
1426 }
1427
1428 break;
1429 }
1430 default:
1431 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type);
1432 rc = -1;
1433 break;
1434 }
1435 return rc;
1436 }
1437
1438 /**
1439 * @ingroup scsi_api_base
1440 * @brief Send read/write data.
1441 *
1442 * @par Description
1443 * This call is made by a target-server to initiate a SCSI read or write data phase, transferring
1444 * data between the target to the remote initiator. The payload is specified by the
1445 * scatter-gather list @c sgl of length @c sgl_count. The @c wire_len argument
1446 * specifies the payload length (independent of the scatter-gather list cumulative length).
1447 * @n @n
1448 * The @c flags argument has one bit, OCS_SCSI_LAST_DATAPHASE, which is a hint to the base
1449 * driver that it may use auto SCSI response features if the hardware supports it.
1450 * @n @n
1451 * Upon completion, the callback function @b cb is called with flags indicating that the
1452 * IO has completed (OCS_SCSI_IO_COMPL) and another data phase or response may be sent;
1453 * that the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP);
1454 * or that the IO was aborted (OCS_SCSI_IO_ABORTED).
1455 *
1456 * @param io Pointer to the IO context.
1457 * @param flags Flags controlling the sending of data.
1458 * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF.
1459 * @param sgl Pointer to the payload scatter-gather list.
1460 * @param sgl_count Count of the scatter-gather list elements.
1461 * @param xwire_len Length of the payload on wire, in bytes.
1462 * @param type HW IO type.
1463 * @param enable_ar Enable auto-response if true.
1464 * @param cb Completion callback.
1465 * @param arg Application-supplied callback data.
1466 *
1467 * @return Returns 0 on success, or a negative error code value on failure.
1468 */
1469
1470 static inline int32_t
ocs_scsi_xfer_data(ocs_io_t * io,uint32_t flags,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t xwire_len,ocs_hw_io_type_e type,int enable_ar,ocs_scsi_io_cb_t cb,void * arg)1471 ocs_scsi_xfer_data(ocs_io_t *io, uint32_t flags,
1472 ocs_scsi_dif_info_t *dif_info,
1473 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t xwire_len,
1474 ocs_hw_io_type_e type, int enable_ar,
1475 ocs_scsi_io_cb_t cb, void *arg)
1476 {
1477 int32_t rc;
1478 ocs_t *ocs;
1479 uint32_t disable_ar_tgt_dif = FALSE;
1480 size_t residual = 0;
1481
1482 if ((dif_info != NULL) && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) {
1483 dif_info = NULL;
1484 }
1485
1486 ocs_assert(io, -1);
1487
1488 if (dif_info != NULL) {
1489 ocs_hw_get(&io->ocs->hw, OCS_HW_DISABLE_AR_TGT_DIF, &disable_ar_tgt_dif);
1490 if (disable_ar_tgt_dif) {
1491 enable_ar = FALSE;
1492 }
1493 }
1494
1495 io->sgl_count = sgl_count;
1496
1497 /* If needed, copy SGL */
1498 if (sgl && (sgl != io->sgl)) {
1499 ocs_assert(sgl_count <= io->sgl_allocated, -1);
1500 ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl));
1501 }
1502
1503 ocs = io->ocs;
1504 ocs_assert(ocs, -1);
1505 ocs_assert(io->node, -1);
1506
1507 scsi_io_trace(io, "%s wire_len %d\n", (type == OCS_HW_IO_TARGET_READ) ? "send" : "recv", xwire_len);
1508
1509 ocs_assert(sgl, -1);
1510 ocs_assert(sgl_count > 0, -1);
1511 ocs_assert(io->exp_xfer_len > io->transferred, -1);
1512
1513 io->hio_type = type;
1514
1515 io->scsi_tgt_cb = cb;
1516 io->scsi_tgt_cb_arg = arg;
1517
1518 rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
1519 if (rc) {
1520 return rc;
1521 }
1522
1523 /* If DIF is used, then save lba for error recovery */
1524 if (dif_info) {
1525 io->scsi_dif_info = *dif_info;
1526 }
1527
1528 io->wire_len = MIN(xwire_len, io->exp_xfer_len - io->transferred);
1529 residual = (xwire_len - io->wire_len);
1530
1531 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1532 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1533 io->iparam.fcp_tgt.offset = io->transferred;
1534 io->iparam.fcp_tgt.dif_oper = io->hw_dif.dif;
1535 io->iparam.fcp_tgt.blk_size = io->hw_dif.blk_size;
1536 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1537 io->iparam.fcp_tgt.timeout = io->timeout;
1538
1539 /* if this is the last data phase and there is no residual, enable
1540 * auto-good-response
1541 */
1542 if (enable_ar && (flags & OCS_SCSI_LAST_DATAPHASE) &&
1543 (residual == 0) && ((io->transferred + io->wire_len) == io->exp_xfer_len) && (!(flags & OCS_SCSI_NO_AUTO_RESPONSE))) {
1544 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
1545 io->auto_resp = TRUE;
1546 } else {
1547 io->auto_resp = FALSE;
1548 }
1549
1550 /* save this transfer length */
1551 io->xfer_req = io->wire_len;
1552
1553 /* Adjust the transferred count to account for overrun
1554 * when the residual is calculated in ocs_scsi_send_resp
1555 */
1556 io->transferred += residual;
1557
1558 /* Adjust the SGL size if there is overrun */
1559
1560 if (residual) {
1561 ocs_scsi_sgl_t *sgl_ptr = &io->sgl[sgl_count-1];
1562
1563 while (residual) {
1564 size_t len = sgl_ptr->len;
1565 if ( len > residual) {
1566 sgl_ptr->len = len - residual;
1567 residual = 0;
1568 } else {
1569 sgl_ptr->len = 0;
1570 residual -= len;
1571 io->sgl_count--;
1572 }
1573 sgl_ptr--;
1574 }
1575 }
1576
1577 /* Set latency and WQ steering */
1578 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
1579 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
1580 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
1581
1582 return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1583 }
1584
1585
1586 int32_t
ocs_scsi_send_rd_data(ocs_io_t * io,uint32_t flags,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t len,ocs_scsi_io_cb_t cb,void * arg)1587 ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags,
1588 ocs_scsi_dif_info_t *dif_info,
1589 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
1590 ocs_scsi_io_cb_t cb, void *arg)
1591 {
1592 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_READ,
1593 enable_tsend_auto_resp(io->ocs), cb, arg);
1594 }
1595
1596 int32_t
ocs_scsi_recv_wr_data(ocs_io_t * io,uint32_t flags,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t len,ocs_scsi_io_cb_t cb,void * arg)1597 ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags,
1598 ocs_scsi_dif_info_t *dif_info,
1599 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len,
1600 ocs_scsi_io_cb_t cb, void *arg)
1601 {
1602 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_WRITE,
1603 enable_treceive_auto_resp(io->ocs), cb, arg);
1604 }
1605
1606 /**
1607 * @ingroup scsi_api_base
1608 * @brief Free overflow SGL.
1609 *
1610 * @par Description
1611 * Free the overflow SGL if it is present.
1612 *
1613 * @param io Pointer to IO object.
1614 *
1615 * @return None.
1616 */
1617 static void
ocs_scsi_io_free_ovfl(ocs_io_t * io)1618 ocs_scsi_io_free_ovfl(ocs_io_t *io) {
1619 if (io->ovfl_sgl.size) {
1620 ocs_dma_free(io->ocs, &io->ovfl_sgl);
1621 }
1622 }
1623
1624 /**
1625 * @ingroup scsi_api_base
1626 * @brief Send response data.
1627 *
1628 * @par Description
1629 * This function is used by a target-server to send the SCSI response data to a remote
1630 * initiator node. The target-server populates the @c ocs_scsi_cmd_resp_t
1631 * argument with scsi status, status qualifier, sense data, and response data, as
1632 * needed.
1633 * @n @n
1634 * Upon completion, the callback function @c cb is invoked. The target-server will generally
1635 * clean up its IO context resources and call ocs_scsi_io_complete().
1636 *
1637 * @param io Pointer to the IO context.
1638 * @param flags Flags to control sending of the SCSI response.
1639 * @param rsp Pointer to the response data populated by the caller.
1640 * @param cb Completion callback.
1641 * @param arg Application-specified completion callback argument.
1642
1643 * @return Returns 0 on success, or a negative error code value on failure.
1644 */
1645 int32_t
ocs_scsi_send_resp(ocs_io_t * io,uint32_t flags,ocs_scsi_cmd_resp_t * rsp,ocs_scsi_io_cb_t cb,void * arg)1646 ocs_scsi_send_resp(ocs_io_t *io, uint32_t flags, ocs_scsi_cmd_resp_t *rsp, ocs_scsi_io_cb_t cb, void *arg)
1647 {
1648 ocs_t *ocs;
1649 int32_t residual;
1650 int auto_resp = TRUE; /* Always try auto resp */
1651 uint8_t scsi_status = 0;
1652 uint16_t scsi_status_qualifier = 0;
1653 uint8_t *sense_data = NULL;
1654 uint32_t sense_data_length = 0;
1655
1656 ocs_assert(io, -1);
1657
1658 ocs = io->ocs;
1659 ocs_assert(ocs, -1);
1660
1661 ocs_assert(io->node, -1);
1662
1663 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
1664
1665 if (rsp) {
1666 scsi_status = rsp->scsi_status;
1667 scsi_status_qualifier = rsp->scsi_status_qualifier;
1668 sense_data = rsp->sense_data;
1669 sense_data_length = rsp->sense_data_length;
1670 residual = rsp->residual;
1671 } else {
1672 residual = io->exp_xfer_len - io->transferred;
1673 }
1674
1675 io->wire_len = 0;
1676 io->hio_type = OCS_HW_IO_TARGET_RSP;
1677
1678 io->scsi_tgt_cb = cb;
1679 io->scsi_tgt_cb_arg = arg;
1680
1681 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1682 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1683 io->iparam.fcp_tgt.offset = 0;
1684 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1685 io->iparam.fcp_tgt.timeout = io->timeout;
1686
1687 /* Set low latency queueing request */
1688 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0;
1689 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT;
1690 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT;
1691
1692 if ((scsi_status != 0) || residual || sense_data_length) {
1693 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
1694
1695 if (!fcprsp) {
1696 ocs_log_err(ocs, "NULL response buffer\n");
1697 return -1;
1698 }
1699
1700 auto_resp = FALSE;
1701
1702 ocs_memset(fcprsp, 0, sizeof(*fcprsp));
1703
1704 io->wire_len += (sizeof(*fcprsp) - sizeof(fcprsp->data));
1705
1706 fcprsp->scsi_status = scsi_status;
1707 *((uint16_t*)fcprsp->status_qualifier) = ocs_htobe16(scsi_status_qualifier);
1708
1709 /* set residual status if necessary */
1710 if (residual != 0) {
1711 /* FCP: if data transferred is less than the amount expected, then this is an
1712 * underflow. If data transferred would have been greater than the amount expected
1713 * then this is an overflow
1714 */
1715 if (residual > 0) {
1716 fcprsp->flags |= FCP_RESID_UNDER;
1717 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(residual);
1718 } else {
1719 fcprsp->flags |= FCP_RESID_OVER;
1720 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(-residual);
1721 }
1722 }
1723
1724 if (sense_data && sense_data_length) {
1725 ocs_assert(sense_data_length <= sizeof(fcprsp->data), -1);
1726 fcprsp->flags |= FCP_SNS_LEN_VALID;
1727 ocs_memcpy(fcprsp->data, sense_data, sense_data_length);
1728 *((uint32_t*)fcprsp->fcp_sns_len) = ocs_htobe32(sense_data_length);
1729 io->wire_len += sense_data_length;
1730 }
1731
1732 io->sgl[0].addr = io->rspbuf.phys;
1733 io->sgl[0].dif_addr = 0;
1734 io->sgl[0].len = io->wire_len;
1735 io->sgl_count = 1;
1736 }
1737
1738 if (auto_resp) {
1739 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE;
1740 }
1741
1742 return ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1743 }
1744
1745 /**
1746 * @ingroup scsi_api_base
1747 * @brief Send TMF response data.
1748 *
1749 * @par Description
1750 * This function is used by a target-server to send SCSI TMF response data to a remote
1751 * initiator node.
1752 * Upon completion, the callback function @c cb is invoked. The target-server will generally
1753 * clean up its IO context resources and call ocs_scsi_io_complete().
1754 *
1755 * @param io Pointer to the IO context.
1756 * @param rspcode TMF response code.
1757 * @param addl_rsp_info Additional TMF response information (may be NULL for zero data).
1758 * @param cb Completion callback.
1759 * @param arg Application-specified completion callback argument.
1760 *
1761 * @return Returns 0 on success, or a negative error code value on failure.
1762 */
1763 int32_t
ocs_scsi_send_tmf_resp(ocs_io_t * io,ocs_scsi_tmf_resp_e rspcode,uint8_t addl_rsp_info[3],ocs_scsi_io_cb_t cb,void * arg)1764 ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3],
1765 ocs_scsi_io_cb_t cb, void *arg)
1766 {
1767 int32_t rc = -1;
1768 ocs_t *ocs = NULL;
1769 fcp_rsp_iu_t *fcprsp = NULL;
1770 fcp_rsp_info_t *rspinfo = NULL;
1771 uint8_t fcp_rspcode;
1772
1773 ocs_assert(io, -1);
1774 ocs_assert(io->ocs, -1);
1775 ocs_assert(io->node, -1);
1776
1777 ocs = io->ocs;
1778
1779 io->wire_len = 0;
1780 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif);
1781
1782 switch(rspcode) {
1783 case OCS_SCSI_TMF_FUNCTION_COMPLETE:
1784 fcp_rspcode = FCP_TMF_COMPLETE;
1785 break;
1786 case OCS_SCSI_TMF_FUNCTION_SUCCEEDED:
1787 case OCS_SCSI_TMF_FUNCTION_IO_NOT_FOUND:
1788 fcp_rspcode = FCP_TMF_SUCCEEDED;
1789 break;
1790 case OCS_SCSI_TMF_FUNCTION_REJECTED:
1791 fcp_rspcode = FCP_TMF_REJECTED;
1792 break;
1793 case OCS_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER:
1794 fcp_rspcode = FCP_TMF_INCORRECT_LUN;
1795 break;
1796 case OCS_SCSI_TMF_SERVICE_DELIVERY:
1797 fcp_rspcode = FCP_TMF_FAILED;
1798 break;
1799 default:
1800 fcp_rspcode = FCP_TMF_REJECTED;
1801 break;
1802 }
1803
1804 io->hio_type = OCS_HW_IO_TARGET_RSP;
1805
1806 io->scsi_tgt_cb = cb;
1807 io->scsi_tgt_cb_arg = arg;
1808
1809 if (io->tmf_cmd == OCS_SCSI_TMF_ABORT_TASK) {
1810 rc = ocs_target_send_bls_resp(io, cb, arg);
1811 return rc;
1812 }
1813
1814 /* populate the FCP TMF response */
1815 fcprsp = io->rspbuf.virt;
1816 ocs_memset(fcprsp, 0, sizeof(*fcprsp));
1817
1818 fcprsp->flags |= FCP_RSP_LEN_VALID;
1819
1820 rspinfo = (fcp_rsp_info_t*) fcprsp->data;
1821 if (addl_rsp_info != NULL) {
1822 ocs_memcpy(rspinfo->addl_rsp_info, addl_rsp_info, sizeof(rspinfo->addl_rsp_info));
1823 }
1824 rspinfo->rsp_code = fcp_rspcode;
1825
1826 io->wire_len = sizeof(*fcprsp) - sizeof(fcprsp->data) + sizeof(*rspinfo);
1827
1828 *((uint32_t*)fcprsp->fcp_rsp_len) = ocs_htobe32(sizeof(*rspinfo));
1829
1830 io->sgl[0].addr = io->rspbuf.phys;
1831 io->sgl[0].dif_addr = 0;
1832 io->sgl[0].len = io->wire_len;
1833 io->sgl_count = 1;
1834
1835 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
1836 io->iparam.fcp_tgt.ox_id = io->init_task_tag;
1837 io->iparam.fcp_tgt.offset = 0;
1838 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl;
1839 io->iparam.fcp_tgt.timeout = io->timeout;
1840
1841 rc = ocs_scsi_io_dispatch(io, ocs_target_io_cb);
1842
1843 return rc;
1844 }
1845
1846
1847 /**
1848 * @brief Process target abort callback.
1849 *
1850 * @par Description
1851 * Accepts HW abort requests.
1852 *
1853 * @param hio HW IO context.
1854 * @param rnode Remote node.
1855 * @param length Length of response data.
1856 * @param status Completion status.
1857 * @param ext_status Extended completion status.
1858 * @param app Application-specified callback data.
1859 *
1860 * @return Returns 0 on success, or a negative error code value on failure.
1861 */
1862
1863 static int32_t
ocs_target_abort_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)1864 ocs_target_abort_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
1865 {
1866 ocs_io_t *io = app;
1867 ocs_t *ocs;
1868 ocs_scsi_io_status_e scsi_status;
1869
1870 ocs_assert(io, -1);
1871 ocs_assert(io->ocs, -1);
1872
1873 ocs = io->ocs;
1874
1875 if (io->abort_cb) {
1876 ocs_scsi_io_cb_t abort_cb = io->abort_cb;
1877 void *abort_cb_arg = io->abort_cb_arg;
1878
1879 io->abort_cb = NULL;
1880 io->abort_cb_arg = NULL;
1881
1882 switch (status) {
1883 case SLI4_FC_WCQE_STATUS_SUCCESS:
1884 scsi_status = OCS_SCSI_STATUS_GOOD;
1885 break;
1886 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
1887 switch (ext_status) {
1888 case SLI4_FC_LOCAL_REJECT_NO_XRI:
1889 scsi_status = OCS_SCSI_STATUS_NO_IO;
1890 break;
1891 case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS:
1892 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
1893 break;
1894 default:
1895 /* TODO: we have seen 0x15 (abort in progress) */
1896 scsi_status = OCS_SCSI_STATUS_ERROR;
1897 break;
1898 }
1899 break;
1900 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
1901 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
1902 break;
1903 default:
1904 scsi_status = OCS_SCSI_STATUS_ERROR;
1905 break;
1906 }
1907 /* invoke callback */
1908 abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg);
1909 }
1910
1911 ocs_assert(io != io->io_to_abort, -1);
1912
1913 /* done with IO to abort */
1914 ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_tgt_abort_io() */
1915
1916 ocs_io_free(ocs, io);
1917
1918 ocs_scsi_check_pending(ocs);
1919 return 0;
1920 }
1921
1922 /**
1923 * @ingroup scsi_api_base
1924 * @brief Abort a target IO.
1925 *
1926 * @par Description
1927 * This routine is called from a SCSI target-server. It initiates an abort of a
1928 * previously-issued target data phase or response request.
1929 *
1930 * @param io IO context.
1931 * @param cb SCSI target server callback.
1932 * @param arg SCSI target server supplied callback argument.
1933 *
1934 * @return Returns 0 on success, or a non-zero value on failure.
1935 */
1936 int32_t
ocs_scsi_tgt_abort_io(ocs_io_t * io,ocs_scsi_io_cb_t cb,void * arg)1937 ocs_scsi_tgt_abort_io(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
1938 {
1939 ocs_t *ocs;
1940 ocs_xport_t *xport;
1941 int32_t rc;
1942
1943 ocs_io_t *abort_io = NULL;
1944 ocs_assert(io, -1);
1945 ocs_assert(io->node, -1);
1946 ocs_assert(io->ocs, -1);
1947
1948 ocs = io->ocs;
1949 xport = ocs->xport;
1950
1951 /* take a reference on IO being aborted */
1952 if ((ocs_ref_get_unless_zero(&io->ref) == 0)) {
1953 /* command no longer active */
1954 scsi_io_printf(io, "command no longer active\n");
1955 return -1;
1956 }
1957
1958 /*
1959 * allocate a new IO to send the abort request. Use ocs_io_alloc() directly, as
1960 * we need an IO object that will not fail allocation due to allocations being
1961 * disabled (in ocs_scsi_io_alloc())
1962 */
1963 abort_io = ocs_io_alloc(ocs);
1964 if (abort_io == NULL) {
1965 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1);
1966 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
1967 return -1;
1968 }
1969
1970 /* Save the target server callback and argument */
1971 ocs_assert(abort_io->hio == NULL, -1);
1972
1973 /* set generic fields */
1974 abort_io->cmd_tgt = TRUE;
1975 abort_io->node = io->node;
1976
1977 /* set type and abort-specific fields */
1978 abort_io->io_type = OCS_IO_TYPE_ABORT;
1979 abort_io->display_name = "tgt_abort";
1980 abort_io->io_to_abort = io;
1981 abort_io->send_abts = FALSE;
1982 abort_io->abort_cb = cb;
1983 abort_io->abort_cb_arg = arg;
1984
1985 /* now dispatch IO */
1986 rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_target_abort_cb);
1987 if (rc) {
1988 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
1989 }
1990 return rc;
1991 }
1992
1993 /**
1994 * @brief Process target BLS response callback.
1995 *
1996 * @par Description
1997 * Accepts HW abort requests.
1998 *
1999 * @param hio HW IO context.
2000 * @param rnode Remote node.
2001 * @param length Length of response data.
2002 * @param status Completion status.
2003 * @param ext_status Extended completion status.
2004 * @param app Application-specified callback data.
2005 *
2006 * @return Returns 0 on success, or a negative error code value on failure.
2007 */
2008
2009 static int32_t
ocs_target_bls_resp_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)2010 ocs_target_bls_resp_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, int32_t status, uint32_t ext_status, void *app)
2011 {
2012 ocs_io_t *io = app;
2013 ocs_t *ocs;
2014 ocs_scsi_io_status_e bls_status;
2015
2016 ocs_assert(io, -1);
2017 ocs_assert(io->ocs, -1);
2018
2019 ocs = io->ocs;
2020
2021 /* BLS isn't really a "SCSI" concept, but use SCSI status */
2022 if (status) {
2023 io_error_log(io, "s=%#x x=%#x\n", status, ext_status);
2024 bls_status = OCS_SCSI_STATUS_ERROR;
2025 } else {
2026 bls_status = OCS_SCSI_STATUS_GOOD;
2027 }
2028
2029 if (io->bls_cb) {
2030 ocs_scsi_io_cb_t bls_cb = io->bls_cb;
2031 void *bls_cb_arg = io->bls_cb_arg;
2032
2033 io->bls_cb = NULL;
2034 io->bls_cb_arg = NULL;
2035
2036 /* invoke callback */
2037 bls_cb(io, bls_status, 0, bls_cb_arg);
2038 }
2039
2040 ocs_scsi_check_pending(ocs);
2041 return 0;
2042 }
2043
2044 /**
2045 * @brief Complete abort request.
2046 *
2047 * @par Description
2048 * An abort request is completed by posting a BA_ACC for the IO that requested the abort.
2049 *
2050 * @param io Pointer to the IO context.
2051 * @param cb Callback function to invoke upon completion.
2052 * @param arg Application-specified completion callback argument.
2053 *
2054 * @return Returns 0 on success, or a negative error code value on failure.
2055 */
2056
2057 static int32_t
ocs_target_send_bls_resp(ocs_io_t * io,ocs_scsi_io_cb_t cb,void * arg)2058 ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg)
2059 {
2060 int32_t rc;
2061 fc_ba_acc_payload_t *acc;
2062
2063 ocs_assert(io, -1);
2064
2065 /* fill out IO structure with everything needed to send BA_ACC */
2066 ocs_memset(&io->iparam, 0, sizeof(io->iparam));
2067 io->iparam.bls.ox_id = io->init_task_tag;
2068 io->iparam.bls.rx_id = io->abort_rx_id;
2069
2070 acc = (void *)io->iparam.bls.payload;
2071
2072 ocs_memset(io->iparam.bls.payload, 0, sizeof(io->iparam.bls.payload));
2073 acc->ox_id = io->iparam.bls.ox_id;
2074 acc->rx_id = io->iparam.bls.rx_id;
2075 acc->high_seq_cnt = UINT16_MAX;
2076
2077 /* generic io fields have already been populated */
2078
2079 /* set type and BLS-specific fields */
2080 io->io_type = OCS_IO_TYPE_BLS_RESP;
2081 io->display_name = "bls_rsp";
2082 io->hio_type = OCS_HW_BLS_ACC;
2083 io->bls_cb = cb;
2084 io->bls_cb_arg = arg;
2085
2086 /* dispatch IO */
2087 rc = ocs_scsi_io_dispatch(io, ocs_target_bls_resp_cb);
2088 return rc;
2089 }
2090
2091 /**
2092 * @ingroup scsi_api_base
2093 * @brief Notify the base driver that the IO is complete.
2094 *
2095 * @par Description
2096 * This function is called by a target-server to notify the base driver that an IO
2097 * has completed, allowing for the base driver to free resources.
2098 * @n
2099 * @n @b Note: This function is not called by initiator-clients.
2100 *
2101 * @param io Pointer to IO context.
2102 *
2103 * @return None.
2104 */
2105 void
ocs_scsi_io_complete(ocs_io_t * io)2106 ocs_scsi_io_complete(ocs_io_t *io)
2107 {
2108 ocs_assert(io);
2109
2110 if (!ocs_io_busy(io)) {
2111 ocs_log_test(io->ocs, "Got completion for non-busy io with tag 0x%x\n", io->tag);
2112 return;
2113 }
2114
2115 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name);
2116 ocs_assert(ocs_ref_read_count(&io->ref) > 0);
2117 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */
2118 }
2119
2120
2121 /**
2122 * @brief Handle initiator IO completion.
2123 *
2124 * @par Description
2125 * This callback is made upon completion of an initiator operation (initiator read/write command).
2126 *
2127 * @param hio HW IO context.
2128 * @param rnode Remote node.
2129 * @param length Length of completion data.
2130 * @param status Completion status.
2131 * @param ext_status Extended completion status.
2132 * @param app Application-specified callback data.
2133 *
2134 * @return None.
2135 */
2136
2137 static void
ocs_initiator_io_cb(ocs_hw_io_t * hio,ocs_remote_node_t * rnode,uint32_t length,int32_t status,uint32_t ext_status,void * app)2138 ocs_initiator_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length,
2139 int32_t status, uint32_t ext_status, void *app)
2140 {
2141 ocs_io_t *io = app;
2142 ocs_t *ocs;
2143 ocs_scsi_io_status_e scsi_status;
2144
2145 ocs_assert(io);
2146 ocs_assert(io->scsi_ini_cb);
2147
2148 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status);
2149
2150 ocs = io->ocs;
2151 ocs_assert(ocs);
2152
2153 ocs_scsi_io_free_ovfl(io);
2154
2155 /* Call target server completion */
2156 if (io->scsi_ini_cb) {
2157 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt;
2158 ocs_scsi_cmd_resp_t rsp;
2159 ocs_scsi_rsp_io_cb_t cb = io->scsi_ini_cb;
2160 uint32_t flags = 0;
2161 uint8_t *pd = fcprsp->data;
2162
2163 /* Clear the callback before invoking the callback */
2164 io->scsi_ini_cb = NULL;
2165
2166 ocs_memset(&rsp, 0, sizeof(rsp));
2167
2168 /* Unless status is FCP_RSP_FAILURE, fcprsp is not filled in */
2169 switch (status) {
2170 case SLI4_FC_WCQE_STATUS_SUCCESS:
2171 scsi_status = OCS_SCSI_STATUS_GOOD;
2172 break;
2173 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE:
2174 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE;
2175 rsp.scsi_status = fcprsp->scsi_status;
2176 rsp.scsi_status_qualifier = ocs_be16toh(*((uint16_t*)fcprsp->status_qualifier));
2177
2178 if (fcprsp->flags & FCP_RSP_LEN_VALID) {
2179 rsp.response_data = pd;
2180 rsp.response_data_length = ocs_fc_getbe32(fcprsp->fcp_rsp_len);
2181 pd += rsp.response_data_length;
2182 }
2183 if (fcprsp->flags & FCP_SNS_LEN_VALID) {
2184 uint32_t sns_len = ocs_fc_getbe32(fcprsp->fcp_sns_len);
2185 rsp.sense_data = pd;
2186 rsp.sense_data_length = sns_len;
2187 pd += sns_len;
2188 }
2189 /* Set residual */
2190 if (fcprsp->flags & FCP_RESID_OVER) {
2191 rsp.residual = -ocs_fc_getbe32(fcprsp->fcp_resid);
2192 rsp.response_wire_length = length;
2193 } else if (fcprsp->flags & FCP_RESID_UNDER) {
2194 rsp.residual = ocs_fc_getbe32(fcprsp->fcp_resid);
2195 rsp.response_wire_length = length;
2196 }
2197
2198 /*
2199 * Note: The FCP_RSP_FAILURE can be returned for initiator IOs when the total data
2200 * placed does not match the requested length even if the status is good. If
2201 * the status is all zeroes, then we have to assume that a frame(s) were
2202 * dropped and change the status to LOCAL_REJECT/OUT_OF_ORDER_DATA
2203 */
2204 if (length != io->wire_len) {
2205 uint32_t rsp_len = ext_status;
2206 uint8_t *rsp_bytes = io->rspbuf.virt;
2207 uint32_t i;
2208 uint8_t all_zeroes = (rsp_len > 0);
2209 /* Check if the rsp is zero */
2210 for (i = 0; i < rsp_len; i++) {
2211 if (rsp_bytes[i] != 0) {
2212 all_zeroes = FALSE;
2213 break;
2214 }
2215 }
2216 if (all_zeroes) {
2217 scsi_status = OCS_SCSI_STATUS_ERROR;
2218 ocs_log_test(io->ocs, "[%s]" SCSI_IOFMT "local reject=0x%02x\n",
2219 io->node->display_name, SCSI_IOFMT_ARGS(io),
2220 SLI4_FC_LOCAL_REJECT_OUT_OF_ORDER_DATA);
2221 }
2222 }
2223 break;
2224 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
2225 if (ext_status == SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT) {
2226 scsi_status = OCS_SCSI_STATUS_COMMAND_TIMEOUT;
2227 } else {
2228 scsi_status = OCS_SCSI_STATUS_ERROR;
2229 }
2230 break;
2231 case SLI4_FC_WCQE_STATUS_DI_ERROR:
2232 if (ext_status & 0x01) {
2233 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR;
2234 } else if (ext_status & 0x02) {
2235 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR;
2236 } else if (ext_status & 0x04) {
2237 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR;
2238 } else {
2239 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR;
2240 }
2241 break;
2242 default:
2243 scsi_status = OCS_SCSI_STATUS_ERROR;
2244 break;
2245 }
2246
2247 cb(io, scsi_status, &rsp, flags, io->scsi_ini_cb_arg);
2248
2249 }
2250 ocs_scsi_check_pending(ocs);
2251 }
2252
2253 /**
2254 * @ingroup scsi_api_base
2255 * @brief Initiate initiator read IO.
2256 *
2257 * @par Description
2258 * This call is made by an initiator-client to send a SCSI read command. The payload
2259 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2260 * entries.
2261 * @n @n
2262 * Upon completion, the callback @b cb is invoked and passed request status.
2263 * If the command completed successfully, the callback is given SCSI response data.
2264 *
2265 * @param node Pointer to the node.
2266 * @param io Pointer to the IO context.
2267 * @param lun LUN value.
2268 * @param cdb Pointer to the CDB.
2269 * @param cdb_len Length of the CDB.
2270 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2271 * @param sgl Pointer to the scatter-gather list.
2272 * @param sgl_count Count of the scatter-gather list elements.
2273 * @param wire_len Length of the payload.
2274 * @param cb Completion callback.
2275 * @param arg Application-specified completion callback argument.
2276 *
2277 * @return Returns 0 on success, or a negative error code value on failure.
2278 */
2279 int32_t
ocs_scsi_send_rd_io(ocs_node_t * node,ocs_io_t * io,uint64_t lun,void * cdb,uint32_t cdb_len,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t wire_len,ocs_scsi_rsp_io_cb_t cb,void * arg)2280 ocs_scsi_send_rd_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2281 ocs_scsi_dif_info_t *dif_info,
2282 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
2283 ocs_scsi_rsp_io_cb_t cb, void *arg)
2284 {
2285 int32_t rc;
2286
2287 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2288 wire_len, 0, cb, arg);
2289
2290 return rc;
2291 }
2292
2293 /**
2294 * @ingroup scsi_api_base
2295 * @brief Initiate initiator write IO.
2296 *
2297 * @par Description
2298 * This call is made by an initiator-client to send a SCSI write command. The payload
2299 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2300 * entries.
2301 * @n @n
2302 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2303 * completed successfully, the callback is given SCSI response data.
2304 *
2305 * @param node Pointer to the node.
2306 * @param io Pointer to IO context.
2307 * @param lun LUN value.
2308 * @param cdb Pointer to the CDB.
2309 * @param cdb_len Length of the CDB.
2310 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2311 * @param sgl Pointer to the scatter-gather list.
2312 * @param sgl_count Count of the scatter-gather list elements.
2313 * @param wire_len Length of the payload.
2314 * @param cb Completion callback.
2315 * @param arg Application-specified completion callback argument.
2316 *
2317 * @return Returns 0 on success, or a negative error code value on failure.
2318 */
ocs_scsi_send_wr_io(ocs_node_t * node,ocs_io_t * io,uint64_t lun,void * cdb,uint32_t cdb_len,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t wire_len,ocs_scsi_rsp_io_cb_t cb,void * arg)2319 int32_t ocs_scsi_send_wr_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2320 ocs_scsi_dif_info_t *dif_info,
2321 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len,
2322 ocs_scsi_rsp_io_cb_t cb, void *arg)
2323 {
2324 int32_t rc;
2325
2326 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2327 wire_len, 0, cb, arg);
2328
2329 return rc;
2330 }
2331
2332 /**
2333 * @ingroup scsi_api_base
2334 * @brief Initiate initiator write IO.
2335 *
2336 * @par Description
2337 * This call is made by an initiator-client to send a SCSI write command. The payload
2338 * for the command is given by a scatter-gather list @c sgl for @c sgl_count
2339 * entries.
2340 * @n @n
2341 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2342 * completed successfully, the callback is given SCSI response data.
2343 *
2344 * @param node Pointer to the node.
2345 * @param io Pointer to IO context.
2346 * @param lun LUN value.
2347 * @param cdb Pointer to the CDB.
2348 * @param cdb_len Length of the CDB.
2349 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2350 * @param sgl Pointer to the scatter-gather list.
2351 * @param sgl_count Count of the scatter-gather list elements.
2352 * @param wire_len Length of the payload.
2353 * @param first_burst Number of first burst bytes to send.
2354 * @param cb Completion callback.
2355 * @param arg Application-specified completion callback argument.
2356 *
2357 * @return Returns 0 on success, or a negative error code value on failure.
2358 */
2359 int32_t
ocs_scsi_send_wr_io_first_burst(ocs_node_t * node,ocs_io_t * io,uint64_t lun,void * cdb,uint32_t cdb_len,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t wire_len,uint32_t first_burst,ocs_scsi_rsp_io_cb_t cb,void * arg)2360 ocs_scsi_send_wr_io_first_burst(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2361 ocs_scsi_dif_info_t *dif_info,
2362 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
2363 ocs_scsi_rsp_io_cb_t cb, void *arg)
2364 {
2365 int32_t rc;
2366
2367 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_WRITE, node, io, lun, 0, cdb, cdb_len, dif_info, sgl, sgl_count,
2368 wire_len, 0, cb, arg);
2369
2370 return rc;
2371 }
2372
2373 /**
2374 * @ingroup scsi_api_base
2375 * @brief Initiate initiator SCSI command with no data.
2376 *
2377 * @par Description
2378 * This call is made by an initiator-client to send a SCSI command with no data.
2379 * @n @n
2380 * Upon completion, the callback @c cb is invoked and passed request status. If the command
2381 * completed successfully, the callback is given SCSI response data.
2382 *
2383 * @param node Pointer to the node.
2384 * @param io Pointer to the IO context.
2385 * @param lun LUN value.
2386 * @param cdb Pointer to the CDB.
2387 * @param cdb_len Length of the CDB.
2388 * @param cb Completion callback.
2389 * @param arg Application-specified completion callback argument.
2390 *
2391 * @return Returns 0 on success, or a negative error code value on failure.
2392 */
ocs_scsi_send_nodata_io(ocs_node_t * node,ocs_io_t * io,uint64_t lun,void * cdb,uint32_t cdb_len,ocs_scsi_rsp_io_cb_t cb,void * arg)2393 int32_t ocs_scsi_send_nodata_io(ocs_node_t *node, ocs_io_t *io, uint64_t lun, void *cdb, uint32_t cdb_len,
2394 ocs_scsi_rsp_io_cb_t cb, void *arg)
2395 {
2396 int32_t rc;
2397
2398 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_NODATA, node, io, lun, 0, cdb, cdb_len, NULL, NULL, 0, 0, 0, cb, arg);
2399
2400 return rc;
2401 }
2402 /**
2403 * @ingroup scsi_api_base
2404 * @brief Initiate initiator task management operation.
2405 *
2406 * @par Description
2407 * This command is used to send a SCSI task management function command. If the command
2408 * requires it (QUERY_TASK_SET for example), a payload may be associated with the command.
2409 * If no payload is required, then @c sgl_count may be zero and @c sgl is ignored.
2410 * @n @n
2411 * Upon completion @c cb is invoked with status and SCSI response data.
2412 *
2413 * @param node Pointer to the node.
2414 * @param io Pointer to the IO context.
2415 * @param io_to_abort Pointer to the IO context to abort in the
2416 * case of OCS_SCSI_TMF_ABORT_TASK. Note: this can point to the
2417 * same the same ocs_io_t as @c io, provided that @c io does not
2418 * have any outstanding work requests.
2419 * @param lun LUN value.
2420 * @param tmf Task management command.
2421 * @param sgl Pointer to the scatter-gather list.
2422 * @param sgl_count Count of the scatter-gather list elements.
2423 * @param len Length of the payload.
2424 * @param cb Completion callback.
2425 * @param arg Application-specified completion callback argument.
2426 *
2427 * @return Returns 0 on success, or a negative error code value on failure.
2428 */
2429 int32_t
ocs_scsi_send_tmf(ocs_node_t * node,ocs_io_t * io,ocs_io_t * io_to_abort,uint64_t lun,ocs_scsi_tmf_cmd_e tmf,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t len,ocs_scsi_rsp_io_cb_t cb,void * arg)2430 ocs_scsi_send_tmf(ocs_node_t *node, ocs_io_t *io, ocs_io_t *io_to_abort, uint64_t lun, ocs_scsi_tmf_cmd_e tmf,
2431 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, ocs_scsi_rsp_io_cb_t cb, void *arg)
2432 {
2433 int32_t rc;
2434 ocs_assert(io, -1);
2435
2436 if (tmf == OCS_SCSI_TMF_ABORT_TASK) {
2437 ocs_assert(io_to_abort, -1);
2438
2439 /* take a reference on IO being aborted */
2440 if ((ocs_ref_get_unless_zero(&io_to_abort->ref) == 0)) {
2441 /* command no longer active */
2442 scsi_io_printf(io, "command no longer active\n");
2443 return -1;
2444 }
2445 /* generic io fields have already been populated */
2446
2447 /* abort-specific fields */
2448 io->io_type = OCS_IO_TYPE_ABORT;
2449 io->display_name = "abort_task";
2450 io->io_to_abort = io_to_abort;
2451 io->send_abts = TRUE;
2452 io->scsi_ini_cb = cb;
2453 io->scsi_ini_cb_arg = arg;
2454
2455 /* now dispatch IO */
2456 rc = ocs_scsi_io_dispatch_abort(io, ocs_scsi_abort_io_cb);
2457 if (rc) {
2458 scsi_io_printf(io, "Failed to dispatch abort\n");
2459 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */
2460 }
2461 } else {
2462 io->display_name = "tmf";
2463 rc = ocs_scsi_send_io(OCS_HW_IO_INITIATOR_READ, node, io, lun, tmf, NULL, 0, NULL,
2464 sgl, sgl_count, len, 0, cb, arg);
2465 }
2466
2467 return rc;
2468 }
2469
2470 /**
2471 * @ingroup scsi_api_base
2472 * @brief Send an FCP IO.
2473 *
2474 * @par Description
2475 * An FCP read/write IO command, with optional task management flags, is sent to @c node.
2476 *
2477 * @param type HW IO type to send.
2478 * @param node Pointer to the node destination of the IO.
2479 * @param io Pointer to the IO context.
2480 * @param lun LUN value.
2481 * @param tmf Task management command.
2482 * @param cdb Pointer to the SCSI CDB.
2483 * @param cdb_len Length of the CDB, in bytes.
2484 * @param dif_info Pointer to the T10 DIF fields, or NULL if no DIF.
2485 * @param sgl Pointer to the scatter-gather list.
2486 * @param sgl_count Number of SGL entries in SGL.
2487 * @param wire_len Payload length, in bytes, of data on wire.
2488 * @param first_burst Number of first burst bytes to send.
2489 * @param cb Completion callback.
2490 * @param arg Application-specified completion callback argument.
2491 *
2492 * @return Returns 0 on success, or a negative error code value on failure.
2493 */
2494
2495 /* tc: could elminiate LUN, as it's part of the IO structure */
2496
ocs_scsi_send_io(ocs_hw_io_type_e type,ocs_node_t * node,ocs_io_t * io,uint64_t lun,ocs_scsi_tmf_cmd_e tmf,uint8_t * cdb,uint32_t cdb_len,ocs_scsi_dif_info_t * dif_info,ocs_scsi_sgl_t * sgl,uint32_t sgl_count,uint32_t wire_len,uint32_t first_burst,ocs_scsi_rsp_io_cb_t cb,void * arg)2497 static int32_t ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun,
2498 ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len,
2499 ocs_scsi_dif_info_t *dif_info,
2500 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst,
2501 ocs_scsi_rsp_io_cb_t cb, void *arg)
2502 {
2503 int32_t rc;
2504 ocs_t *ocs;
2505 fcp_cmnd_iu_t *cmnd;
2506 uint32_t cmnd_bytes = 0;
2507 uint32_t *fcp_dl;
2508 uint8_t tmf_flags = 0;
2509
2510 ocs_assert(io->node, -1);
2511 ocs_assert(io->node == node, -1);
2512 ocs_assert(io, -1);
2513 ocs = io->ocs;
2514 ocs_assert(cb, -1);
2515
2516 io->sgl_count = sgl_count;
2517
2518 /* Copy SGL if needed */
2519 if (sgl != io->sgl) {
2520 ocs_assert(sgl_count <= io->sgl_allocated, -1);
2521 ocs_memcpy(io->sgl, sgl, sizeof(*io->sgl) * sgl_count);
2522 }
2523
2524 /* save initiator and target task tags for debugging */
2525 io->tgt_task_tag = 0xffff;
2526
2527 io->wire_len = wire_len;
2528 io->hio_type = type;
2529
2530 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) {
2531 char buf[80];
2532 ocs_textbuf_t txtbuf;
2533 uint32_t i;
2534
2535 ocs_textbuf_init(ocs, &txtbuf, buf, sizeof(buf));
2536
2537 ocs_textbuf_printf(&txtbuf, "cdb%d: ", cdb_len);
2538 for (i = 0; i < cdb_len; i ++) {
2539 ocs_textbuf_printf(&txtbuf, "%02X%s", cdb[i], (i == (cdb_len-1)) ? "" : " ");
2540 }
2541 scsi_io_printf(io, "%s len %d, %s\n", (io->hio_type == OCS_HW_IO_INITIATOR_READ) ? "read" :
2542 (io->hio_type == OCS_HW_IO_INITIATOR_WRITE) ? "write" : "", io->wire_len,
2543 ocs_textbuf_get_buffer(&txtbuf));
2544 }
2545
2546
2547 ocs_assert(io->cmdbuf.virt, -1);
2548
2549 cmnd = io->cmdbuf.virt;
2550
2551 ocs_assert(sizeof(*cmnd) <= io->cmdbuf.size, -1);
2552
2553 ocs_memset(cmnd, 0, sizeof(*cmnd));
2554
2555 /* Default FCP_CMND IU doesn't include additional CDB bytes but does include FCP_DL */
2556 cmnd_bytes = sizeof(fcp_cmnd_iu_t) - sizeof(cmnd->fcp_cdb_and_dl) + sizeof(uint32_t);
2557
2558 fcp_dl = (uint32_t*)(&(cmnd->fcp_cdb_and_dl));
2559
2560 if (cdb) {
2561 if (cdb_len <= 16) {
2562 ocs_memcpy(cmnd->fcp_cdb, cdb, cdb_len);
2563 } else {
2564 uint32_t addl_cdb_bytes;
2565
2566 ocs_memcpy(cmnd->fcp_cdb, cdb, 16);
2567 addl_cdb_bytes = cdb_len - 16;
2568 ocs_memcpy(cmnd->fcp_cdb_and_dl, &(cdb[16]), addl_cdb_bytes);
2569 /* additional_fcp_cdb_length is in words, not bytes */
2570 cmnd->additional_fcp_cdb_length = (addl_cdb_bytes + 3) / 4;
2571 fcp_dl += cmnd->additional_fcp_cdb_length;
2572
2573 /* Round up additional CDB bytes */
2574 cmnd_bytes += (addl_cdb_bytes + 3) & ~0x3;
2575 }
2576 }
2577
2578 be64enc(cmnd->fcp_lun, CAM_EXTLUN_BYTE_SWIZZLE(lun));
2579
2580 if (node->fcp2device) {
2581 if(ocs_get_crn(node, &cmnd->command_reference_number,
2582 lun)) {
2583 return -1;
2584 }
2585 }
2586
2587 switch (tmf) {
2588 case OCS_SCSI_TMF_QUERY_TASK_SET:
2589 tmf_flags = FCP_QUERY_TASK_SET;
2590 break;
2591 case OCS_SCSI_TMF_ABORT_TASK_SET:
2592 tmf_flags = FCP_ABORT_TASK_SET;
2593 break;
2594 case OCS_SCSI_TMF_CLEAR_TASK_SET:
2595 tmf_flags = FCP_CLEAR_TASK_SET;
2596 break;
2597 case OCS_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
2598 tmf_flags = FCP_QUERY_ASYNCHRONOUS_EVENT;
2599 break;
2600 case OCS_SCSI_TMF_LOGICAL_UNIT_RESET:
2601 tmf_flags = FCP_LOGICAL_UNIT_RESET;
2602 break;
2603 case OCS_SCSI_TMF_CLEAR_ACA:
2604 tmf_flags = FCP_CLEAR_ACA;
2605 break;
2606 case OCS_SCSI_TMF_TARGET_RESET:
2607 tmf_flags = FCP_TARGET_RESET;
2608 break;
2609 default:
2610 tmf_flags = 0;
2611 }
2612 cmnd->task_management_flags = tmf_flags;
2613
2614 *fcp_dl = ocs_htobe32(io->wire_len);
2615
2616 switch (io->hio_type) {
2617 case OCS_HW_IO_INITIATOR_READ:
2618 cmnd->rddata = 1;
2619 break;
2620 case OCS_HW_IO_INITIATOR_WRITE:
2621 cmnd->wrdata = 1;
2622 break;
2623 case OCS_HW_IO_INITIATOR_NODATA:
2624 /* sets neither */
2625 break;
2626 default:
2627 ocs_log_test(ocs, "bad IO type %d\n", io->hio_type);
2628 return -1;
2629 }
2630
2631 rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif);
2632 if (rc) {
2633 return rc;
2634 }
2635
2636 io->scsi_ini_cb = cb;
2637 io->scsi_ini_cb_arg = arg;
2638
2639 /* set command and response buffers in the iparam */
2640 io->iparam.fcp_ini.cmnd = &io->cmdbuf;
2641 io->iparam.fcp_ini.cmnd_size = cmnd_bytes;
2642 io->iparam.fcp_ini.rsp = &io->rspbuf;
2643 io->iparam.fcp_ini.flags = 0;
2644 io->iparam.fcp_ini.dif_oper = io->hw_dif.dif;
2645 io->iparam.fcp_ini.blk_size = io->hw_dif.blk_size;
2646 io->iparam.fcp_ini.timeout = io->timeout;
2647 io->iparam.fcp_ini.first_burst = first_burst;
2648
2649 return ocs_scsi_io_dispatch(io, ocs_initiator_io_cb);
2650 }
2651
2652 /**
2653 * @ingroup scsi_api_base
2654 * @brief Callback for an aborted IO.
2655 *
2656 * @par Description
2657 * Callback function invoked upon completion of an IO abort request.
2658 *
2659 * @param hio HW IO context.
2660 * @param rnode Remote node.
2661 * @param len Response length.
2662 * @param status Completion status.
2663 * @param ext_status Extended completion status.
2664 * @param arg Application-specific callback, usually IO context.
2665
2666 * @return Returns 0 on success, or a negative error code value on failure.
2667 */
2668
2669 static int32_t
ocs_scsi_abort_io_cb(struct ocs_hw_io_s * hio,ocs_remote_node_t * rnode,uint32_t len,int32_t status,uint32_t ext_status,void * arg)2670 ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status,
2671 uint32_t ext_status, void *arg)
2672 {
2673 ocs_io_t *io = arg;
2674 ocs_t *ocs;
2675 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD;
2676
2677 ocs_assert(io, -1);
2678 ocs_assert(ocs_io_busy(io), -1);
2679 ocs_assert(io->ocs, -1);
2680 ocs_assert(io->io_to_abort, -1);
2681 ocs = io->ocs;
2682
2683 ocs_log_debug(ocs, "status %d ext %d\n", status, ext_status);
2684
2685 /* done with IO to abort */
2686 ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_send_tmf() */
2687
2688 ocs_scsi_io_free_ovfl(io);
2689
2690 switch (status) {
2691 case SLI4_FC_WCQE_STATUS_SUCCESS:
2692 scsi_status = OCS_SCSI_STATUS_GOOD;
2693 break;
2694 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT:
2695 if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED) {
2696 scsi_status = OCS_SCSI_STATUS_ABORTED;
2697 } else if (ext_status == SLI4_FC_LOCAL_REJECT_NO_XRI) {
2698 scsi_status = OCS_SCSI_STATUS_NO_IO;
2699 } else if (ext_status == SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS) {
2700 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS;
2701 } else {
2702 ocs_log_test(ocs, "Unhandled local reject 0x%x/0x%x\n", status, ext_status);
2703 scsi_status = OCS_SCSI_STATUS_ERROR;
2704 }
2705 break;
2706 default:
2707 scsi_status = OCS_SCSI_STATUS_ERROR;
2708 break;
2709 }
2710
2711 if (io->scsi_ini_cb) {
2712 (*io->scsi_ini_cb)(io, scsi_status, NULL, 0, io->scsi_ini_cb_arg);
2713 } else {
2714 ocs_scsi_io_free(io);
2715 }
2716
2717 ocs_scsi_check_pending(ocs);
2718 return 0;
2719 }
2720
2721 /**
2722 * @ingroup scsi_api_base
2723 * @brief Return SCSI API integer valued property.
2724 *
2725 * @par Description
2726 * This function is called by a target-server or initiator-client to
2727 * retrieve an integer valued property.
2728 *
2729 * @param ocs Pointer to the ocs.
2730 * @param prop Property value to return.
2731 *
2732 * @return Returns a value, or 0 if invalid property was requested.
2733 */
2734 uint32_t
ocs_scsi_get_property(ocs_t * ocs,ocs_scsi_property_e prop)2735 ocs_scsi_get_property(ocs_t *ocs, ocs_scsi_property_e prop)
2736 {
2737 ocs_xport_t *xport = ocs->xport;
2738 uint32_t val;
2739
2740 switch (prop) {
2741 case OCS_SCSI_MAX_SGE:
2742 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGE, &val)) {
2743 return val;
2744 }
2745 break;
2746 case OCS_SCSI_MAX_SGL:
2747 if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
2748 /*
2749 * If chain SGL test-mode is enabled, the number of HW SGEs
2750 * has been limited; report back original max.
2751 */
2752 return (OCS_FC_MAX_SGL);
2753 }
2754 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &val)) {
2755 return val;
2756 }
2757 break;
2758 case OCS_SCSI_MAX_IOS:
2759 return ocs_io_pool_allocated(xport->io_pool);
2760 case OCS_SCSI_DIF_CAPABLE:
2761 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &val)) {
2762 return val;
2763 }
2764 break;
2765 case OCS_SCSI_MAX_FIRST_BURST:
2766 return 0;
2767 case OCS_SCSI_DIF_MULTI_SEPARATE:
2768 if (ocs_hw_get(&ocs->hw, OCS_HW_DIF_MULTI_SEPARATE, &val) == 0) {
2769 return val;
2770 }
2771 break;
2772 case OCS_SCSI_ENABLE_TASK_SET_FULL:
2773 /* Return FALSE if we are send frame capable */
2774 if (ocs_hw_get(&ocs->hw, OCS_HW_SEND_FRAME_CAPABLE, &val) == 0) {
2775 return ! val;
2776 }
2777 break;
2778 default:
2779 break;
2780 }
2781
2782 ocs_log_debug(ocs, "invalid property request %d\n", prop);
2783 return 0;
2784 }
2785
2786 /**
2787 * @ingroup scsi_api_base
2788 * @brief Return a property pointer.
2789 *
2790 * @par Description
2791 * This function is called by a target-server or initiator-client to
2792 * retrieve a pointer to the requested property.
2793 *
2794 * @param ocs Pointer to the ocs.
2795 * @param prop Property value to return.
2796 *
2797 * @return Returns pointer to the requested property, or NULL otherwise.
2798 */
ocs_scsi_get_property_ptr(ocs_t * ocs,ocs_scsi_property_e prop)2799 void *ocs_scsi_get_property_ptr(ocs_t *ocs, ocs_scsi_property_e prop)
2800 {
2801 void *rc = NULL;
2802
2803 switch (prop) {
2804 case OCS_SCSI_WWNN:
2805 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_NODE);
2806 break;
2807 case OCS_SCSI_WWPN:
2808 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_WWN_PORT);
2809 break;
2810 case OCS_SCSI_PORTNUM:
2811 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_PORTNUM);
2812 break;
2813 case OCS_SCSI_BIOS_VERSION_STRING:
2814 rc = ocs_hw_get_ptr(&ocs->hw, OCS_HW_BIOS_VERSION_STRING);
2815 break;
2816 #if defined(OCS_ENABLE_VPD_SUPPORT)
2817 case OCS_SCSI_SERIALNUMBER:
2818 {
2819 uint8_t *pvpd;
2820 uint32_t vpd_len;
2821
2822 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
2823 ocs_log_test(ocs, "Can't get VPD length\n");
2824 rc = "\012sn-unknown";
2825 break;
2826 }
2827
2828 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
2829 if (pvpd) {
2830 rc = ocs_find_vpd(pvpd, vpd_len, "SN");
2831 }
2832
2833 if (rc == NULL ||
2834 ocs_strlen(rc) == 0) {
2835 /* Note: VPD is missing, using wwnn for serial number */
2836 scsi_log(ocs, "Note: VPD is missing, using wwnn for serial number\n");
2837 /* Use the last 32 bits of the WWN */
2838 if ((ocs == NULL) || (ocs->domain == NULL) || (ocs->domain->sport == NULL)) {
2839 rc = "\011(Unknown)";
2840 } else {
2841 rc = &ocs->domain->sport->wwnn_str[8];
2842 }
2843 }
2844 break;
2845 }
2846 case OCS_SCSI_PARTNUMBER:
2847 {
2848 uint8_t *pvpd;
2849 uint32_t vpd_len;
2850
2851 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) {
2852 ocs_log_test(ocs, "Can't get VPD length\n");
2853 rc = "\012pn-unknown";
2854 break;
2855 }
2856 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD);
2857 if (pvpd) {
2858 rc = ocs_find_vpd(pvpd, vpd_len, "PN");
2859 if (rc == NULL) {
2860 rc = "\012pn-unknown";
2861 }
2862 } else {
2863 rc = "\012pn-unknown";
2864 }
2865 break;
2866 }
2867 #endif
2868 default:
2869 break;
2870 }
2871
2872 if (rc == NULL) {
2873 ocs_log_debug(ocs, "invalid property request %d\n", prop);
2874 }
2875 return rc;
2876 }
2877
2878 /**
2879 * @ingroup scsi_api_base
2880 * @brief Notify that delete initiator is complete.
2881 *
2882 * @par Description
2883 * Sent by the target-server to notify the base driver that the work started from
2884 * ocs_scsi_del_initiator() is now complete and that it is safe for the node to
2885 * release the rest of its resources.
2886 *
2887 * @param node Pointer to the node.
2888 *
2889 * @return None.
2890 */
2891 void
ocs_scsi_del_initiator_complete(ocs_node_t * node)2892 ocs_scsi_del_initiator_complete(ocs_node_t *node)
2893 {
2894 /* Notify the node to resume */
2895 ocs_node_post_event(node, OCS_EVT_NODE_DEL_INI_COMPLETE, NULL);
2896 }
2897
2898
2899 /**
2900 * @ingroup scsi_api_base
2901 * @brief Notify that delete target is complete.
2902 *
2903 * @par Description
2904 * Sent by the initiator-client to notify the base driver that the work started from
2905 * ocs_scsi_del_target() is now complete and that it is safe for the node to
2906 * release the rest of its resources.
2907 *
2908 * @param node Pointer to the node.
2909 *
2910 * @return None.
2911 */
2912 void
ocs_scsi_del_target_complete(ocs_node_t * node)2913 ocs_scsi_del_target_complete(ocs_node_t *node)
2914 {
2915 /* Notify the node to resume */
2916 ocs_node_post_event(node, OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL);
2917 }
2918
2919
2920 /**
2921 * @brief Update transferred count
2922 *
2923 * @par Description
2924 * Updates io->transferred, as required when using first burst, when the amount
2925 * of first burst data processed differs from the amount of first burst
2926 * data received.
2927 *
2928 * @param io Pointer to the io object.
2929 * @param transferred Number of bytes transferred out of first burst buffers.
2930 *
2931 * @return None.
2932 */
2933 void
ocs_scsi_update_first_burst_transferred(ocs_io_t * io,uint32_t transferred)2934 ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred)
2935 {
2936 io->transferred = transferred;
2937 }
2938
2939 /**
2940 * @brief Register bounce callback for multi-threading.
2941 *
2942 * @par Description
2943 * Register the back end bounce function.
2944 *
2945 * @param ocs Pointer to device object.
2946 * @param fctn Function pointer of bounce function.
2947 *
2948 * @return None.
2949 */
2950 void
ocs_scsi_register_bounce(ocs_t * ocs,void (* fctn)(void (* fctn)(void * arg),void * arg,uint32_t s_id,uint32_t d_id,uint32_t ox_id))2951 ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void(*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id,
2952 uint32_t ox_id))
2953 {
2954 ocs_hw_rtn_e rc;
2955
2956 rc = ocs_hw_callback(&ocs->hw, OCS_HW_CB_BOUNCE, fctn, NULL);
2957 if (rc) {
2958 ocs_log_test(ocs, "ocs_hw_callback(OCS_HW_CB_BOUNCE) failed: %d\n", rc);
2959 }
2960 }
2961