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