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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 */ 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 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 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 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 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 */ 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 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 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 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 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