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