1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 /** 35 * @file 36 * OCS Linux SCSI API base driver implementation. 37 */ 38 39 /** 40 * @defgroup scsi_api_base SCSI Base Target/Initiator 41 */ 42 43 #include "ocs.h" 44 #include "ocs_els.h" 45 #include "ocs_scsi.h" 46 #if defined(OCS_ENABLE_VPD_SUPPORT) 47 #include "ocs_vpd.h" 48 #endif 49 #include "ocs_utils.h" 50 #include "ocs_device.h" 51 52 #define SCSI_IOFMT "[%04x][i:%0*x t:%0*x h:%04x]" 53 #define SCSI_ITT_SIZE(ocs) ((ocs->ocs_xport == OCS_XPORT_FC) ? 4 : 8) 54 55 #define SCSI_IOFMT_ARGS(io) io->instance_index, SCSI_ITT_SIZE(io->ocs), io->init_task_tag, SCSI_ITT_SIZE(io->ocs), io->tgt_task_tag, io->hw_tag 56 57 #define enable_tsend_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TSEND) == 0) 58 #define enable_treceive_auto_resp(ocs) ((ocs->ctrlmask & OCS_CTRLMASK_XPORT_DISABLE_AUTORSP_TRECEIVE) == 0) 59 60 #define scsi_io_printf(io, fmt, ...) ocs_log_info(io->ocs, "[%s]" SCSI_IOFMT fmt, \ 61 io->node->display_name, SCSI_IOFMT_ARGS(io), ##__VA_ARGS__) 62 63 #define scsi_io_trace(io, fmt, ...) \ 64 do { \ 65 if (OCS_LOG_ENABLE_SCSI_TRACE(io->ocs)) \ 66 scsi_io_printf(io, fmt, ##__VA_ARGS__); \ 67 } while (0) 68 69 #define scsi_log(ocs, fmt, ...) \ 70 do { \ 71 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) \ 72 ocs_log_info(ocs, fmt, ##__VA_ARGS__); \ 73 } while (0) 74 75 static int32_t ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg); 76 static int32_t ocs_scsi_abort_io_cb(struct ocs_hw_io_s *hio, ocs_remote_node_t *rnode, uint32_t len, int32_t status, 77 uint32_t ext, void *arg); 78 79 static void ocs_scsi_io_free_ovfl(ocs_io_t *io); 80 static uint32_t ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count); 81 static int ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info); 82 static ocs_scsi_io_status_e ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc); 83 static uint32_t ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[], 84 uint32_t addrlen_count, ocs_dif_t *dif, int is_crc); 85 static uint32_t ocs_scsi_dif_check_app_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint16_t exp_app_tag, ocs_dif_t *dif); 86 static uint32_t ocs_scsi_dif_check_ref_tag(ocs_t *ocs, ocs_hw_dif_info_t *dif_info, uint32_t exp_ref_tag, ocs_dif_t *dif); 87 static int32_t ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, 88 ocs_hw_dif_info_t *hw_dif_info); 89 static int32_t ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio); 90 static int32_t ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io); 91 static void _ocs_scsi_io_free(void *arg); 92 93 /** 94 * @ingroup scsi_api_base 95 * @brief Returns a big-endian 32-bit value given a pointer. 96 * 97 * @param p Pointer to the 32-bit big-endian location. 98 * 99 * @return Returns the byte-swapped 32-bit value. 100 */ 101 102 static inline uint32_t 103 ocs_fc_getbe32(void *p) 104 { 105 return ocs_be32toh(*((uint32_t*)p)); 106 } 107 108 /** 109 * @ingroup scsi_api_base 110 * @brief Enable IO allocation. 111 * 112 * @par Description 113 * The SCSI and Transport IO allocation functions are enabled. If the allocation functions 114 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will 115 * fail. 116 * 117 * @param node Pointer to node object. 118 * 119 * @return None. 120 */ 121 void 122 ocs_scsi_io_alloc_enable(ocs_node_t *node) 123 { 124 ocs_assert(node != NULL); 125 ocs_lock(&node->active_ios_lock); 126 node->io_alloc_enabled = TRUE; 127 ocs_unlock(&node->active_ios_lock); 128 } 129 130 /** 131 * @ingroup scsi_api_base 132 * @brief Disable IO allocation 133 * 134 * @par Description 135 * The SCSI and Transport IO allocation functions are disabled. If the allocation functions 136 * are not enabled, then calls to ocs_scsi_io_alloc() (and ocs_els_io_alloc() for FC) will 137 * fail. 138 * 139 * @param node Pointer to node object 140 * 141 * @return None. 142 */ 143 void 144 ocs_scsi_io_alloc_disable(ocs_node_t *node) 145 { 146 ocs_assert(node != NULL); 147 ocs_lock(&node->active_ios_lock); 148 node->io_alloc_enabled = FALSE; 149 ocs_unlock(&node->active_ios_lock); 150 } 151 152 /** 153 * @ingroup scsi_api_base 154 * @brief Allocate a SCSI IO context. 155 * 156 * @par Description 157 * A SCSI IO context is allocated and associated with a @c node. This function 158 * is called by an initiator-client when issuing SCSI commands to remote 159 * target devices. On completion, ocs_scsi_io_free() is called. 160 * @n @n 161 * The returned ocs_io_t structure has an element of type ocs_scsi_ini_io_t named 162 * "ini_io" that is declared and used by an initiator-client for private information. 163 * 164 * @param node Pointer to the associated node structure. 165 * @param role Role for IO (originator/responder). 166 * 167 * @return Returns the pointer to the IO context, or NULL. 168 * 169 */ 170 171 ocs_io_t * 172 ocs_scsi_io_alloc(ocs_node_t *node, ocs_scsi_io_role_e role) 173 { 174 ocs_t *ocs; 175 ocs_xport_t *xport; 176 ocs_io_t *io; 177 178 ocs_assert(node, NULL); 179 ocs_assert(node->ocs, NULL); 180 181 ocs = node->ocs; 182 ocs_assert(ocs->xport, NULL); 183 xport = ocs->xport; 184 185 ocs_lock(&node->active_ios_lock); 186 187 if (!node->io_alloc_enabled) { 188 ocs_unlock(&node->active_ios_lock); 189 return NULL; 190 } 191 192 io = ocs_io_alloc(ocs); 193 if (io == NULL) { 194 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1); 195 ocs_unlock(&node->active_ios_lock); 196 return NULL; 197 } 198 199 /* initialize refcount */ 200 ocs_ref_init(&io->ref, _ocs_scsi_io_free, io); 201 202 if (io->hio != NULL) { 203 ocs_log_err(node->ocs, "assertion failed: io->hio is not NULL\n"); 204 ocs_io_free(ocs, io); 205 ocs_unlock(&node->active_ios_lock); 206 return NULL; 207 } 208 209 /* set generic fields */ 210 io->ocs = ocs; 211 io->node = node; 212 213 /* set type and name */ 214 io->io_type = OCS_IO_TYPE_IO; 215 io->display_name = "scsi_io"; 216 217 switch (role) { 218 case OCS_SCSI_IO_ROLE_ORIGINATOR: 219 io->cmd_ini = TRUE; 220 io->cmd_tgt = FALSE; 221 break; 222 case OCS_SCSI_IO_ROLE_RESPONDER: 223 io->cmd_ini = FALSE; 224 io->cmd_tgt = TRUE; 225 break; 226 } 227 228 /* Add to node's active_ios list */ 229 ocs_list_add_tail(&node->active_ios, io); 230 231 ocs_unlock(&node->active_ios_lock); 232 233 return io; 234 } 235 236 /** 237 * @ingroup scsi_api_base 238 * @brief Free a SCSI IO context (internal). 239 * 240 * @par Description 241 * The IO context previously allocated using ocs_scsi_io_alloc() 242 * is freed. This is called from within the transport layer, 243 * when the reference count goes to zero. 244 * 245 * @param arg Pointer to the IO context. 246 * 247 * @return None. 248 */ 249 static void 250 _ocs_scsi_io_free(void *arg) 251 { 252 ocs_io_t *io = (ocs_io_t *)arg; 253 ocs_t *ocs = io->ocs; 254 ocs_node_t *node = io->node; 255 int send_empty_event; 256 257 ocs_assert(io != NULL); 258 259 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name); 260 261 ocs_assert(ocs_io_busy(io)); 262 263 ocs_lock(&node->active_ios_lock); 264 ocs_list_remove(&node->active_ios, io); 265 send_empty_event = (!node->io_alloc_enabled) && ocs_list_empty(&node->active_ios); 266 ocs_unlock(&node->active_ios_lock); 267 268 if (send_empty_event) { 269 ocs_node_post_event(node, OCS_EVT_NODE_ACTIVE_IO_LIST_EMPTY, NULL); 270 } 271 272 io->node = NULL; 273 ocs_io_free(ocs, io); 274 275 } 276 277 /** 278 * @ingroup scsi_api_base 279 * @brief Free a SCSI IO context. 280 * 281 * @par Description 282 * The IO context previously allocated using ocs_scsi_io_alloc() is freed. 283 * 284 * @param io Pointer to the IO context. 285 * 286 * @return None. 287 */ 288 void 289 ocs_scsi_io_free(ocs_io_t *io) 290 { 291 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name); 292 ocs_assert(ocs_ref_read_count(&io->ref) > 0); 293 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */ 294 } 295 296 static int32_t 297 ocs_scsi_send_io(ocs_hw_io_type_e type, ocs_node_t *node, ocs_io_t *io, uint64_t lun, 298 ocs_scsi_tmf_cmd_e tmf, uint8_t *cdb, uint32_t cdb_len, 299 ocs_scsi_dif_info_t *dif_info, 300 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t wire_len, uint32_t first_burst, 301 ocs_scsi_rsp_io_cb_t cb, void *arg, uint32_t flags); 302 303 /** 304 * @brief Target response completion callback. 305 * 306 * @par Description 307 * Function is called upon the completion of a target IO request. 308 * 309 * @param hio Pointer to the HW IO structure. 310 * @param rnode Remote node associated with the IO that is completing. 311 * @param length Length of the response payload. 312 * @param status Completion status. 313 * @param ext_status Extended completion status. 314 * @param app Application-specific data (generally a pointer to the IO context). 315 * 316 * @return None. 317 */ 318 319 static void 320 ocs_target_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, 321 int32_t status, uint32_t ext_status, void *app) 322 { 323 ocs_io_t *io = app; 324 ocs_t *ocs; 325 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_GOOD; 326 uint16_t additional_length; 327 uint8_t edir; 328 uint8_t tdpv; 329 ocs_hw_dif_info_t *dif_info = &io->hw_dif; 330 int is_crc; 331 332 ocs_assert(io); 333 334 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status); 335 336 ocs = io->ocs; 337 ocs_assert(ocs); 338 339 ocs_scsi_io_free_ovfl(io); 340 341 io->transferred += length; 342 343 /* Call target server completion */ 344 if (io->scsi_tgt_cb) { 345 ocs_scsi_io_cb_t cb = io->scsi_tgt_cb; 346 uint32_t flags = 0; 347 348 /* Clear the callback before invoking the callback */ 349 io->scsi_tgt_cb = NULL; 350 351 /* if status was good, and auto-good-response was set, then callback 352 * target-server with IO_CMPL_RSP_SENT, otherwise send IO_CMPL 353 */ 354 if ((status == 0) && (io->auto_resp)) 355 flags |= OCS_SCSI_IO_CMPL_RSP_SENT; 356 else 357 flags |= OCS_SCSI_IO_CMPL; 358 359 switch (status) { 360 case SLI4_FC_WCQE_STATUS_SUCCESS: 361 scsi_status = OCS_SCSI_STATUS_GOOD; 362 break; 363 case SLI4_FC_WCQE_STATUS_DI_ERROR: 364 if (ext_status & SLI4_FC_DI_ERROR_GE) { 365 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR; 366 } else if (ext_status & SLI4_FC_DI_ERROR_AE) { 367 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR; 368 } else if (ext_status & SLI4_FC_DI_ERROR_RE) { 369 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR; 370 } else { 371 additional_length = ((ext_status >> 16) & 0xFFFF); 372 373 /* Capture the EDIR and TDPV bits as 0 or 1 for easier printing. */ 374 edir = !!(ext_status & SLI4_FC_DI_ERROR_EDIR); 375 tdpv = !!(ext_status & SLI4_FC_DI_ERROR_TDPV); 376 377 is_crc = ocs_scsi_dif_guard_is_crc(edir, dif_info); 378 379 if (edir == 0) { 380 /* For reads, we have everything in memory. Start checking from beginning. */ 381 scsi_status = ocs_scsi_dif_check_unknown(io, 0, io->wire_len, is_crc); 382 } else { 383 /* For writes, use the additional length to determine where to look for the error. 384 * The additional_length field is set to 0 if it is not supported. 385 * The additional length field is valid if: 386 * . additional_length is not zero 387 * . Total Data Placed is valid 388 * . Error Direction is RX (1) 389 * . Operation is a pass thru (CRC or CKSUM on IN, and CRC or CHKSUM on OUT) (all pass-thru cases except raw) 390 */ 391 if ((additional_length != 0) && (tdpv != 0) && 392 (dif_info->dif == SLI4_DIF_PASS_THROUGH) && (dif_info->dif_oper != OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW) ) { 393 scsi_status = ocs_scsi_dif_check_unknown(io, length, additional_length, is_crc); 394 } else { 395 /* If we can't do additional checking, then fall-back to guard error */ 396 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR; 397 } 398 } 399 } 400 break; 401 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT: 402 switch (ext_status) { 403 case SLI4_FC_LOCAL_REJECT_INVALID_RELOFFSET: 404 case SLI4_FC_LOCAL_REJECT_ABORT_REQUESTED: 405 scsi_status = OCS_SCSI_STATUS_ABORTED; 406 break; 407 case SLI4_FC_LOCAL_REJECT_INVALID_RPI: 408 scsi_status = OCS_SCSI_STATUS_NEXUS_LOST; 409 break; 410 case SLI4_FC_LOCAL_REJECT_NO_XRI: 411 scsi_status = OCS_SCSI_STATUS_NO_IO; 412 break; 413 default: 414 /* TODO: we have seen 0x0d (TX_DMA_FAILED error) */ 415 scsi_status = OCS_SCSI_STATUS_ERROR; 416 break; 417 } 418 break; 419 420 case SLI4_FC_WCQE_STATUS_TARGET_WQE_TIMEOUT: 421 /* target IO timed out */ 422 scsi_status = OCS_SCSI_STATUS_TIMEDOUT_AND_ABORTED; 423 break; 424 425 case SLI4_FC_WCQE_STATUS_SHUTDOWN: 426 /* Target IO cancelled by HW */ 427 scsi_status = OCS_SCSI_STATUS_SHUTDOWN; 428 break; 429 430 default: 431 scsi_status = OCS_SCSI_STATUS_ERROR; 432 break; 433 } 434 435 cb(io, scsi_status, flags, io->scsi_tgt_cb_arg); 436 } 437 ocs_scsi_check_pending(ocs); 438 } 439 440 /** 441 * @brief Determine if an IO is using CRC for DIF guard format. 442 * 443 * @param direction IO direction: 1 for write, 0 for read. 444 * @param dif_info Pointer to HW DIF info data. 445 * 446 * @return Returns TRUE if using CRC, FALSE if not. 447 */ 448 static int 449 ocs_scsi_dif_guard_is_crc(uint8_t direction, ocs_hw_dif_info_t *dif_info) 450 { 451 int is_crc; 452 453 if (direction) { 454 /* For writes, check if operation is "OUT_CRC" or not */ 455 switch(dif_info->dif_oper) { 456 case OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC: 457 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC: 458 case OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC: 459 is_crc = TRUE; 460 break; 461 default: 462 is_crc = FALSE; 463 break; 464 } 465 } else { 466 /* For reads, check if operation is "IN_CRC" or not */ 467 switch(dif_info->dif_oper) { 468 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF: 469 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC: 470 case OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM: 471 is_crc = TRUE; 472 break; 473 default: 474 is_crc = FALSE; 475 break; 476 } 477 } 478 479 return is_crc; 480 } 481 482 /** 483 * @brief Check a block and DIF data, computing the appropriate SCSI status 484 * 485 * @par Description 486 * This function is used to check blocks and DIF when given an unknown DIF 487 * status using the following logic: 488 * 489 * Given the address of the last good block, and a length of bytes that includes 490 * the block with the DIF error, find the bad block. If a block is found with an 491 * app_tag or ref_tag error, then return the appropriate error. No block is expected 492 * to have a block guard error since hardware "fixes" the crc. So if no block in the 493 * range of blocks has an error, then it is presumed to be a BLOCK GUARD error. 494 * 495 * @param io Pointer to the IO object. 496 * @param length Length of bytes covering the good blocks. 497 * @param check_length Length of bytes that covers the bad block. 498 * @param is_crc True if guard is using CRC format. 499 * 500 * @return Returns SCSI status. 501 */ 502 503 static ocs_scsi_io_status_e 504 ocs_scsi_dif_check_unknown(ocs_io_t *io, uint32_t length, uint32_t check_length, int is_crc) 505 { 506 uint32_t i; 507 ocs_t *ocs = io->ocs; 508 ocs_hw_dif_info_t *dif_info = &io->hw_dif; 509 ocs_scsi_io_status_e scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR; 510 uint32_t blocksize; /* data block size */ 511 uint64_t first_check_block; /* first block following total data placed */ 512 uint64_t last_check_block; /* last block to check */ 513 uint32_t check_count; /* count of blocks to check */ 514 ocs_scsi_vaddr_len_t addrlen[4]; /* address-length pairs returned from target */ 515 int32_t addrlen_count; /* count of address-length pairs */ 516 ocs_dif_t *dif; /* pointer to DIF block returned from target */ 517 ocs_scsi_dif_info_t scsi_dif_info = io->scsi_dif_info; 518 519 blocksize = ocs_hw_dif_mem_blocksize(&io->hw_dif, TRUE); 520 first_check_block = length / blocksize; 521 last_check_block = ((length + check_length) / blocksize); 522 check_count = last_check_block - first_check_block; 523 524 ocs_log_debug(ocs, "blocksize %d first check_block %" PRId64 " last_check_block %" PRId64 " check_count %d\n", 525 blocksize, first_check_block, last_check_block, check_count); 526 527 for (i = first_check_block; i < last_check_block; i++) { 528 addrlen_count = ocs_scsi_get_block_vaddr(io, (scsi_dif_info.lba + i), addrlen, ARRAY_SIZE(addrlen), (void**) &dif); 529 if (addrlen_count < 0) { 530 ocs_log_test(ocs, "ocs_scsi_get_block_vaddr() failed: %d\n", addrlen_count); 531 scsi_status = OCS_SCSI_STATUS_DIF_UNKNOWN_ERROR; 532 break; 533 } 534 535 if (! ocs_scsi_dif_check_guard(dif_info, addrlen, addrlen_count, dif, is_crc)) { 536 ocs_log_debug(ocs, "block guard check error, lba %" PRId64 "\n", scsi_dif_info.lba + i); 537 scsi_status = OCS_SCSI_STATUS_DIF_GUARD_ERROR; 538 break; 539 } 540 if (! ocs_scsi_dif_check_app_tag(ocs, dif_info, scsi_dif_info.app_tag, dif)) { 541 ocs_log_debug(ocs, "app tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i); 542 scsi_status = OCS_SCSI_STATUS_DIF_APP_TAG_ERROR; 543 break; 544 } 545 if (! ocs_scsi_dif_check_ref_tag(ocs, dif_info, (scsi_dif_info.ref_tag + i), dif)) { 546 ocs_log_debug(ocs, "ref tag check error, lba %" PRId64 "\n", scsi_dif_info.lba + i); 547 scsi_status = OCS_SCSI_STATUS_DIF_REF_TAG_ERROR; 548 break; 549 } 550 } 551 return scsi_status; 552 } 553 554 /** 555 * @brief Check the block guard of block data 556 * 557 * @par Description 558 * Using the dif_info for the transfer, check the block guard value. 559 * 560 * @param dif_info Pointer to HW DIF info data. 561 * @param addrlen Array of address length pairs. 562 * @param addrlen_count Number of entries in the addrlen[] array. 563 * @param dif Pointer to the DIF data block being checked. 564 * @param is_crc True if guard is using CRC format. 565 * 566 * @return Returns TRUE if block guard check is ok. 567 */ 568 static uint32_t 569 ocs_scsi_dif_check_guard(ocs_hw_dif_info_t *dif_info, ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count, 570 ocs_dif_t *dif, int is_crc) 571 { 572 uint16_t crc = dif_info->dif_seed; 573 uint32_t i; 574 uint16_t checksum; 575 576 if ((dif == NULL) || !dif_info->check_guard) { 577 return TRUE; 578 } 579 580 if (is_crc) { 581 for (i = 0; i < addrlen_count; i++) { 582 crc = ocs_scsi_dif_calc_crc(addrlen[i].vaddr, addrlen[i].length, crc); 583 } 584 return (crc == ocs_be16toh(dif->crc)); 585 } else { 586 checksum = ocs_scsi_dif_calc_checksum(addrlen, addrlen_count); 587 588 return (checksum == dif->crc); 589 } 590 } 591 592 /** 593 * @brief Check the app tag of dif data 594 * 595 * @par Description 596 * Using the dif_info for the transfer, check the app tag. 597 * 598 * @param ocs Pointer to the ocs structure for logging. 599 * @param dif_info Pointer to HW DIF info data. 600 * @param exp_app_tag The value the app tag is expected to be. 601 * @param dif Pointer to the DIF data block being checked. 602 * 603 * @return Returns TRUE if app tag check is ok. 604 */ 605 static uint32_t 606 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) 607 { 608 if ((dif == NULL) || !dif_info->check_app_tag) { 609 return TRUE; 610 } 611 612 ocs_log_debug(ocs, "expected app tag 0x%x, actual 0x%x\n", 613 exp_app_tag, ocs_be16toh(dif->app_tag)); 614 615 return (exp_app_tag == ocs_be16toh(dif->app_tag)); 616 } 617 618 /** 619 * @brief Check the ref tag of dif data 620 * 621 * @par Description 622 * Using the dif_info for the transfer, check the app tag. 623 * 624 * @param ocs Pointer to the ocs structure for logging. 625 * @param dif_info Pointer to HW DIF info data. 626 * @param exp_ref_tag The value the ref tag is expected to be. 627 * @param dif Pointer to the DIF data block being checked. 628 * 629 * @return Returns TRUE if ref tag check is ok. 630 */ 631 static uint32_t 632 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) 633 { 634 if ((dif == NULL) || !dif_info->check_ref_tag) { 635 return TRUE; 636 } 637 638 if (exp_ref_tag != ocs_be32toh(dif->ref_tag)) { 639 ocs_log_debug(ocs, "expected ref tag 0x%x, actual 0x%x\n", 640 exp_ref_tag, ocs_be32toh(dif->ref_tag)); 641 return FALSE; 642 } else { 643 return TRUE; 644 } 645 } 646 647 /** 648 * @brief Return count of SGE's required for request 649 * 650 * @par Description 651 * An accurate count of SGEs is computed and returned. 652 * 653 * @param hw_dif Pointer to HW dif information. 654 * @param sgl Pointer to SGL from back end. 655 * @param sgl_count Count of SGEs in SGL. 656 * 657 * @return Count of SGEs. 658 */ 659 static uint32_t 660 ocs_scsi_count_sgls(ocs_hw_dif_info_t *hw_dif, ocs_scsi_sgl_t *sgl, uint32_t sgl_count) 661 { 662 uint32_t count = 0; 663 uint32_t i; 664 665 /* Convert DIF Information */ 666 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) { 667 /* If we're not DIF separate, then emit a seed SGE */ 668 if (!hw_dif->dif_separate) { 669 count++; 670 } 671 672 for (i = 0; i < sgl_count; i++) { 673 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */ 674 if (hw_dif->dif_separate) { 675 count += 2; 676 } 677 678 count++; 679 } 680 } else { 681 count = sgl_count; 682 } 683 return count; 684 } 685 686 static int32_t 687 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) 688 { 689 int32_t rc; 690 uint32_t i; 691 ocs_t *ocs = hw->os; 692 uint32_t blocksize = 0; 693 uint32_t blockcount; 694 695 ocs_assert(hio, -1); 696 697 /* Initialize HW SGL */ 698 rc = ocs_hw_io_init_sges(hw, hio, type); 699 if (rc) { 700 ocs_log_err(ocs, "ocs_hw_io_init_sges failed: %d\n", rc); 701 return -1; 702 } 703 704 /* Convert DIF Information */ 705 if (hw_dif->dif_oper != OCS_HW_DIF_OPER_DISABLED) { 706 /* If we're not DIF separate, then emit a seed SGE */ 707 if (!hw_dif->dif_separate) { 708 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif); 709 if (rc) { 710 return rc; 711 } 712 } 713 714 /* if we are doing DIF separate, then figure out the block size so that we 715 * can update the ref tag in the DIF seed SGE. Also verify that the 716 * the sgl lengths are all multiples of the blocksize 717 */ 718 if (hw_dif->dif_separate) { 719 switch(hw_dif->blk_size) { 720 case OCS_HW_DIF_BK_SIZE_512: blocksize = 512; break; 721 case OCS_HW_DIF_BK_SIZE_1024: blocksize = 1024; break; 722 case OCS_HW_DIF_BK_SIZE_2048: blocksize = 2048; break; 723 case OCS_HW_DIF_BK_SIZE_4096: blocksize = 4096; break; 724 case OCS_HW_DIF_BK_SIZE_520: blocksize = 520; break; 725 case OCS_HW_DIF_BK_SIZE_4104: blocksize = 4104; break; 726 default: 727 ocs_log_test(hw->os, "Inavlid hw_dif blocksize %d\n", hw_dif->blk_size); 728 return -1; 729 } 730 for (i = 0; i < sgl_count; i++) { 731 if ((sgl[i].len % blocksize) != 0) { 732 ocs_log_test(hw->os, "sgl[%d] len of %ld is not multiple of blocksize\n", 733 i, sgl[i].len); 734 return -1; 735 } 736 } 737 } 738 739 for (i = 0; i < sgl_count; i++) { 740 ocs_assert(sgl[i].addr, -1); 741 ocs_assert(sgl[i].len, -1); 742 743 /* If DIF is enabled, and DIF is separate, then append a SEED then DIF SGE */ 744 if (hw_dif->dif_separate) { 745 rc = ocs_hw_io_add_seed_sge(hw, hio, hw_dif); 746 if (rc) { 747 return rc; 748 } 749 rc = ocs_hw_io_add_dif_sge(hw, hio, sgl[i].dif_addr); 750 if (rc) { 751 return rc; 752 } 753 /* Update the ref_tag for the next DIF seed SGE */ 754 blockcount = sgl[i].len / blocksize; 755 if (hw_dif->dif_oper == OCS_HW_DIF_OPER_INSERT) { 756 hw_dif->ref_tag_repl += blockcount; 757 } else { 758 hw_dif->ref_tag_cmp += blockcount; 759 } 760 } 761 762 /* Add data SGE */ 763 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len); 764 if (rc) { 765 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n", 766 sgl_count, rc); 767 return rc; 768 } 769 } 770 } else { 771 for (i = 0; i < sgl_count; i++) { 772 ocs_assert(sgl[i].addr, -1); 773 ocs_assert(sgl[i].len, -1); 774 775 /* Add data SGE */ 776 rc = ocs_hw_io_add_sge(hw, hio, sgl[i].addr, sgl[i].len); 777 if (rc) { 778 ocs_log_err(ocs, "ocs_hw_io_add_sge failed: count=%d rc=%d\n", 779 sgl_count, rc); 780 return rc; 781 } 782 } 783 } 784 return 0; 785 } 786 787 /** 788 * @ingroup scsi_api_base 789 * @brief Convert SCSI API T10 DIF information into the FC HW format. 790 * 791 * @param ocs Pointer to the ocs structure for logging. 792 * @param scsi_dif_info Pointer to the SCSI API T10 DIF fields. 793 * @param hw_dif_info Pointer to the FC HW API T10 DIF fields. 794 * 795 * @return Returns 0 on success, or a negative error code value on failure. 796 */ 797 798 static int32_t 799 ocs_scsi_convert_dif_info(ocs_t *ocs, ocs_scsi_dif_info_t *scsi_dif_info, ocs_hw_dif_info_t *hw_dif_info) 800 { 801 uint32_t dif_seed; 802 ocs_memset(hw_dif_info, 0, sizeof(ocs_hw_dif_info_t)); 803 804 if (scsi_dif_info == NULL) { 805 hw_dif_info->dif_oper = OCS_HW_DIF_OPER_DISABLED; 806 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_NA; 807 return 0; 808 } 809 810 /* Convert the DIF operation */ 811 switch(scsi_dif_info->dif_oper) { 812 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CRC: 813 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CRC; 814 hw_dif_info->dif = SLI4_DIF_INSERT; 815 break; 816 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_NODIF: 817 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_NODIF; 818 hw_dif_info->dif = SLI4_DIF_STRIP; 819 break; 820 case OCS_SCSI_DIF_OPER_IN_NODIF_OUT_CHKSUM: 821 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_NODIF_OUT_CHKSUM; 822 hw_dif_info->dif = SLI4_DIF_INSERT; 823 break; 824 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_NODIF: 825 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_NODIF; 826 hw_dif_info->dif = SLI4_DIF_STRIP; 827 break; 828 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CRC: 829 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CRC; 830 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH; 831 break; 832 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CHKSUM: 833 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CHKSUM; 834 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH; 835 break; 836 case OCS_SCSI_DIF_OPER_IN_CRC_OUT_CHKSUM: 837 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CRC_OUT_CHKSUM; 838 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH; 839 break; 840 case OCS_SCSI_DIF_OPER_IN_CHKSUM_OUT_CRC: 841 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_CHKSUM_OUT_CRC; 842 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH; 843 break; 844 case OCS_SCSI_DIF_OPER_IN_RAW_OUT_RAW: 845 hw_dif_info->dif_oper = OCS_HW_SGE_DIF_OP_IN_RAW_OUT_RAW; 846 hw_dif_info->dif = SLI4_DIF_PASS_THROUGH; 847 break; 848 default: 849 ocs_log_test(ocs, "unhandled SCSI DIF operation %d\n", 850 scsi_dif_info->dif_oper); 851 return -1; 852 } 853 854 switch(scsi_dif_info->blk_size) { 855 case OCS_SCSI_DIF_BK_SIZE_512: 856 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_512; 857 break; 858 case OCS_SCSI_DIF_BK_SIZE_1024: 859 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_1024; 860 break; 861 case OCS_SCSI_DIF_BK_SIZE_2048: 862 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_2048; 863 break; 864 case OCS_SCSI_DIF_BK_SIZE_4096: 865 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4096; 866 break; 867 case OCS_SCSI_DIF_BK_SIZE_520: 868 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_520; 869 break; 870 case OCS_SCSI_DIF_BK_SIZE_4104: 871 hw_dif_info->blk_size = OCS_HW_DIF_BK_SIZE_4104; 872 break; 873 default: 874 ocs_log_test(ocs, "unhandled SCSI DIF block size %d\n", 875 scsi_dif_info->blk_size); 876 return -1; 877 } 878 879 /* If the operation is an INSERT the tags provided are the ones that should be 880 * inserted, otherwise they're the ones to be checked against. */ 881 if (hw_dif_info->dif == SLI4_DIF_INSERT ) { 882 hw_dif_info->ref_tag_repl = scsi_dif_info->ref_tag; 883 hw_dif_info->app_tag_repl = scsi_dif_info->app_tag; 884 } else { 885 hw_dif_info->ref_tag_cmp = scsi_dif_info->ref_tag; 886 hw_dif_info->app_tag_cmp = scsi_dif_info->app_tag; 887 } 888 889 hw_dif_info->check_ref_tag = scsi_dif_info->check_ref_tag; 890 hw_dif_info->check_app_tag = scsi_dif_info->check_app_tag; 891 hw_dif_info->check_guard = scsi_dif_info->check_guard; 892 hw_dif_info->auto_incr_ref_tag = 1; 893 hw_dif_info->dif_separate = scsi_dif_info->dif_separate; 894 hw_dif_info->disable_app_ffff = scsi_dif_info->disable_app_ffff; 895 hw_dif_info->disable_app_ref_ffff = scsi_dif_info->disable_app_ref_ffff; 896 897 ocs_hw_get(&ocs->hw, OCS_HW_DIF_SEED, &dif_seed); 898 hw_dif_info->dif_seed = dif_seed; 899 900 return 0; 901 } 902 903 /** 904 * @ingroup scsi_api_base 905 * @brief This function logs the SGLs for an IO. 906 * 907 * @param io Pointer to the IO context. 908 */ 909 static void ocs_log_sgl(ocs_io_t *io) 910 { 911 ocs_hw_io_t *hio = io->hio; 912 sli4_sge_t *data = NULL; 913 uint32_t *dword = NULL; 914 uint32_t i; 915 uint32_t n_sge; 916 917 scsi_io_trace(io, "def_sgl at 0x%x 0x%08x\n", 918 ocs_addr32_hi(hio->def_sgl.phys), 919 ocs_addr32_lo(hio->def_sgl.phys)); 920 n_sge = (hio->sgl == &hio->def_sgl ? hio->n_sge : hio->def_sgl_count); 921 for (i = 0, data = hio->def_sgl.virt; i < n_sge; i++, data++) { 922 dword = (uint32_t*)data; 923 924 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n", 925 i, dword[0], dword[1], dword[2], dword[3]); 926 927 if (dword[2] & (1U << 31)) { 928 break; 929 } 930 } 931 932 if (hio->ovfl_sgl != NULL && 933 hio->sgl == hio->ovfl_sgl) { 934 scsi_io_trace(io, "Overflow at 0x%x 0x%08x\n", 935 ocs_addr32_hi(hio->ovfl_sgl->phys), 936 ocs_addr32_lo(hio->ovfl_sgl->phys)); 937 for (i = 0, data = hio->ovfl_sgl->virt; i < hio->n_sge; i++, data++) { 938 dword = (uint32_t*)data; 939 940 scsi_io_trace(io, "SGL %2d 0x%08x 0x%08x 0x%08x 0x%08x\n", 941 i, dword[0], dword[1], dword[2], dword[3]); 942 if (dword[2] & (1U << 31)) { 943 break; 944 } 945 } 946 } 947 948 } 949 950 /** 951 * @brief Check pending error asynchronous callback function. 952 * 953 * @par Description 954 * Invoke the HW callback function for a given IO. This function is called 955 * from the NOP mailbox completion context. 956 * 957 * @param hw Pointer to HW object. 958 * @param status Completion status. 959 * @param mqe Mailbox completion queue entry. 960 * @param arg General purpose argument. 961 * 962 * @return Returns 0. 963 */ 964 static int32_t 965 ocs_scsi_check_pending_async_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg) 966 { 967 ocs_io_t *io = arg; 968 969 if (io != NULL) { 970 if (io->hw_cb != NULL) { 971 ocs_hw_done_t cb = io->hw_cb; 972 973 io->hw_cb = NULL; 974 cb(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_DISPATCH_ERROR, 0, io); 975 } 976 } 977 return 0; 978 } 979 980 /** 981 * @brief Check for pending IOs to dispatch. 982 * 983 * @par Description 984 * If there are IOs on the pending list, and a HW IO is available, then 985 * dispatch the IOs. 986 * 987 * @param ocs Pointer to the OCS structure. 988 * 989 * @return None. 990 */ 991 992 void 993 ocs_scsi_check_pending(ocs_t *ocs) 994 { 995 ocs_xport_t *xport = ocs->xport; 996 ocs_io_t *io; 997 ocs_hw_io_t *hio; 998 int32_t status; 999 int count = 0; 1000 int dispatch; 1001 1002 /* Guard against recursion */ 1003 if (ocs_atomic_add_return(&xport->io_pending_recursing, 1)) { 1004 /* This function is already running. Decrement and return. */ 1005 ocs_atomic_sub_return(&xport->io_pending_recursing, 1); 1006 return; 1007 } 1008 1009 do { 1010 ocs_lock(&xport->io_pending_lock); 1011 status = 0; 1012 hio = NULL; 1013 io = ocs_list_remove_head(&xport->io_pending_list); 1014 if (io != NULL) { 1015 if (io->io_type == OCS_IO_TYPE_ABORT) { 1016 hio = NULL; 1017 } else { 1018 hio = ocs_hw_io_alloc(&ocs->hw); 1019 if (hio == NULL) { 1020 /* 1021 * No HW IO available. 1022 * Put IO back on the front of pending list 1023 */ 1024 ocs_list_add_head(&xport->io_pending_list, io); 1025 io = NULL; 1026 } else { 1027 hio->eq = io->hw_priv; 1028 } 1029 } 1030 } 1031 /* Must drop the lock before dispatching the IO */ 1032 ocs_unlock(&xport->io_pending_lock); 1033 1034 if (io != NULL) { 1035 count++; 1036 1037 /* 1038 * We pulled an IO off the pending list, 1039 * and either got an HW IO or don't need one 1040 */ 1041 ocs_atomic_sub_return(&xport->io_pending_count, 1); 1042 if (hio == NULL) { 1043 status = ocs_scsi_io_dispatch_no_hw_io(io); 1044 } else { 1045 status = ocs_scsi_io_dispatch_hw_io(io, hio); 1046 } 1047 if (status) { 1048 /* 1049 * Invoke the HW callback, but do so in the separate execution context, 1050 * provided by the NOP mailbox completion processing context by using 1051 * ocs_hw_async_call() 1052 */ 1053 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) { 1054 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n"); 1055 } 1056 } 1057 } 1058 } while (io != NULL); 1059 1060 /* 1061 * If nothing was removed from the list, 1062 * we might be in a case where we need to abort an 1063 * active IO and the abort is on the pending list. 1064 * Look for an abort we can dispatch. 1065 */ 1066 if (count == 0 ) { 1067 dispatch = 0; 1068 1069 ocs_lock(&xport->io_pending_lock); 1070 ocs_list_foreach(&xport->io_pending_list, io) { 1071 if (io->io_type == OCS_IO_TYPE_ABORT) { 1072 if (io->io_to_abort->hio != NULL) { 1073 /* This IO has a HW IO, so it is active. Dispatch the abort. */ 1074 dispatch = 1; 1075 } else { 1076 /* Leave this abort on the pending list and keep looking */ 1077 dispatch = 0; 1078 } 1079 } 1080 if (dispatch) { 1081 ocs_list_remove(&xport->io_pending_list, io); 1082 ocs_atomic_sub_return(&xport->io_pending_count, 1); 1083 break; 1084 } 1085 } 1086 ocs_unlock(&xport->io_pending_lock); 1087 1088 if (dispatch) { 1089 status = ocs_scsi_io_dispatch_no_hw_io(io); 1090 if (status) { 1091 if (ocs_hw_async_call(&ocs->hw, ocs_scsi_check_pending_async_cb, io)) { 1092 ocs_log_test(ocs, "call to ocs_hw_async_call() failed\n"); 1093 } 1094 } 1095 } 1096 } 1097 1098 ocs_atomic_sub_return(&xport->io_pending_recursing, 1); 1099 return; 1100 } 1101 1102 /** 1103 * @brief Attempt to dispatch a non-abort IO 1104 * 1105 * @par Description 1106 * An IO is dispatched: 1107 * - if the pending list is not empty, add IO to pending list 1108 * and call a function to process the pending list. 1109 * - if pending list is empty, try to allocate a HW IO. If none 1110 * is available, place this IO at the tail of the pending IO 1111 * list. 1112 * - if HW IO is available, attach this IO to the HW IO and 1113 * submit it. 1114 * 1115 * @param io Pointer to IO structure. 1116 * @param cb Callback function. 1117 * 1118 * @return Returns 0 on success, a negative error code value on failure. 1119 */ 1120 1121 int32_t 1122 ocs_scsi_io_dispatch(ocs_io_t *io, void *cb) 1123 { 1124 ocs_hw_io_t *hio; 1125 ocs_t *ocs = io->ocs; 1126 ocs_xport_t *xport = ocs->xport; 1127 1128 ocs_assert(io->cmd_tgt || io->cmd_ini, -1); 1129 ocs_assert((io->io_type != OCS_IO_TYPE_ABORT), -1); 1130 io->hw_cb = cb; 1131 1132 /* 1133 * if this IO already has a HW IO, then this is either not the first phase of 1134 * the IO. Send it to the HW. 1135 */ 1136 if (io->hio != NULL) { 1137 return ocs_scsi_io_dispatch_hw_io(io, io->hio); 1138 } 1139 1140 /* 1141 * We don't already have a HW IO associated with the IO. First check 1142 * the pending list. If not empty, add IO to the tail and process the 1143 * pending list. 1144 */ 1145 ocs_lock(&xport->io_pending_lock); 1146 if (!ocs_list_empty(&xport->io_pending_list)) { 1147 /* 1148 * If this is a low latency request, the put at the front of the IO pending 1149 * queue, otherwise put it at the end of the queue. 1150 */ 1151 if (io->low_latency) { 1152 ocs_list_add_head(&xport->io_pending_list, io); 1153 } else { 1154 ocs_list_add_tail(&xport->io_pending_list, io); 1155 } 1156 ocs_unlock(&xport->io_pending_lock); 1157 ocs_atomic_add_return(&xport->io_pending_count, 1); 1158 ocs_atomic_add_return(&xport->io_total_pending, 1); 1159 1160 /* process pending list */ 1161 ocs_scsi_check_pending(ocs); 1162 return 0; 1163 } 1164 ocs_unlock(&xport->io_pending_lock); 1165 1166 /* 1167 * We don't have a HW IO associated with the IO and there's nothing 1168 * on the pending list. Attempt to allocate a HW IO and dispatch it. 1169 */ 1170 hio = ocs_hw_io_alloc(&io->ocs->hw); 1171 if (hio == NULL) { 1172 /* Couldn't get a HW IO. Save this IO on the pending list */ 1173 ocs_lock(&xport->io_pending_lock); 1174 ocs_list_add_tail(&xport->io_pending_list, io); 1175 ocs_unlock(&xport->io_pending_lock); 1176 1177 ocs_atomic_add_return(&xport->io_total_pending, 1); 1178 ocs_atomic_add_return(&xport->io_pending_count, 1); 1179 return 0; 1180 } 1181 1182 /* We successfully allocated a HW IO; dispatch to HW */ 1183 return ocs_scsi_io_dispatch_hw_io(io, hio); 1184 } 1185 1186 /** 1187 * @brief Attempt to dispatch an Abort IO. 1188 * 1189 * @par Description 1190 * An Abort IO is dispatched: 1191 * - if the pending list is not empty, add IO to pending list 1192 * and call a function to process the pending list. 1193 * - if pending list is empty, send abort to the HW. 1194 * 1195 * @param io Pointer to IO structure. 1196 * @param cb Callback function. 1197 * 1198 * @return Returns 0 on success, a negative error code value on failure. 1199 */ 1200 1201 int32_t 1202 ocs_scsi_io_dispatch_abort(ocs_io_t *io, void *cb) 1203 { 1204 ocs_t *ocs = io->ocs; 1205 ocs_xport_t *xport = ocs->xport; 1206 1207 ocs_assert((io->io_type == OCS_IO_TYPE_ABORT), -1); 1208 io->hw_cb = cb; 1209 1210 /* 1211 * For aborts, we don't need a HW IO, but we still want to pass through 1212 * the pending list to preserve ordering. Thus, if the pending list is 1213 * not empty, add this abort to the pending list and process the pending list. 1214 */ 1215 ocs_lock(&xport->io_pending_lock); 1216 if (!ocs_list_empty(&xport->io_pending_list)) { 1217 ocs_list_add_tail(&xport->io_pending_list, io); 1218 ocs_unlock(&xport->io_pending_lock); 1219 ocs_atomic_add_return(&xport->io_pending_count, 1); 1220 ocs_atomic_add_return(&xport->io_total_pending, 1); 1221 1222 /* process pending list */ 1223 ocs_scsi_check_pending(ocs); 1224 return 0; 1225 } 1226 ocs_unlock(&xport->io_pending_lock); 1227 1228 /* nothing on pending list, dispatch abort */ 1229 return ocs_scsi_io_dispatch_no_hw_io(io); 1230 1231 } 1232 1233 /** 1234 * @brief Dispatch IO 1235 * 1236 * @par Description 1237 * An IO and its associated HW IO is dispatched to the HW. 1238 * 1239 * @param io Pointer to IO structure. 1240 * @param hio Pointer to HW IO structure from which IO will be 1241 * dispatched. 1242 * 1243 * @return Returns 0 on success, a negative error code value on failure. 1244 */ 1245 1246 static int32_t 1247 ocs_scsi_io_dispatch_hw_io(ocs_io_t *io, ocs_hw_io_t *hio) 1248 { 1249 int32_t rc; 1250 ocs_t *ocs = io->ocs; 1251 1252 /* Got a HW IO; update ini/tgt_task_tag with HW IO info and dispatch */ 1253 io->hio = hio; 1254 if (io->cmd_tgt) { 1255 io->tgt_task_tag = hio->indicator; 1256 } else if (io->cmd_ini) { 1257 io->init_task_tag = hio->indicator; 1258 } 1259 io->hw_tag = hio->reqtag; 1260 1261 hio->eq = io->hw_priv; 1262 1263 /* Copy WQ steering */ 1264 switch(io->wq_steering) { 1265 case OCS_SCSI_WQ_STEERING_CLASS >> OCS_SCSI_WQ_STEERING_SHIFT: 1266 hio->wq_steering = OCS_HW_WQ_STEERING_CLASS; 1267 break; 1268 case OCS_SCSI_WQ_STEERING_REQUEST >> OCS_SCSI_WQ_STEERING_SHIFT: 1269 hio->wq_steering = OCS_HW_WQ_STEERING_REQUEST; 1270 break; 1271 case OCS_SCSI_WQ_STEERING_CPU >> OCS_SCSI_WQ_STEERING_SHIFT: 1272 hio->wq_steering = OCS_HW_WQ_STEERING_CPU; 1273 break; 1274 } 1275 1276 switch (io->io_type) { 1277 case OCS_IO_TYPE_IO: { 1278 uint32_t max_sgl; 1279 uint32_t total_count; 1280 uint32_t host_allocated; 1281 1282 ocs_hw_get(&ocs->hw, OCS_HW_N_SGL, &max_sgl); 1283 ocs_hw_get(&ocs->hw, OCS_HW_SGL_CHAINING_HOST_ALLOCATED, &host_allocated); 1284 1285 /* 1286 * If the requested SGL is larger than the default size, then we can allocate 1287 * an overflow SGL. 1288 */ 1289 total_count = ocs_scsi_count_sgls(&io->hw_dif, io->sgl, io->sgl_count); 1290 1291 /* 1292 * Lancer requires us to allocate the chained memory area, but 1293 * Skyhawk must use the SGL list associated with another XRI. 1294 */ 1295 if (host_allocated && total_count > max_sgl) { 1296 /* Compute count needed, the number extra plus 1 for the link sge */ 1297 uint32_t count = total_count - max_sgl + 1; 1298 rc = ocs_dma_alloc(ocs, &io->ovfl_sgl, count*sizeof(sli4_sge_t), 64); 1299 if (rc) { 1300 ocs_log_err(ocs, "ocs_dma_alloc overflow sgl failed\n"); 1301 break; 1302 } 1303 rc = ocs_hw_io_register_sgl(&ocs->hw, io->hio, &io->ovfl_sgl, count); 1304 if (rc) { 1305 ocs_scsi_io_free_ovfl(io); 1306 ocs_log_err(ocs, "ocs_hw_io_register_sgl() failed\n"); 1307 break; 1308 } 1309 /* EVT: update chained_io_count */ 1310 io->node->chained_io_count++; 1311 } 1312 1313 rc = ocs_scsi_build_sgls(&ocs->hw, io->hio, &io->hw_dif, io->sgl, io->sgl_count, io->hio_type); 1314 if (rc) { 1315 ocs_scsi_io_free_ovfl(io); 1316 break; 1317 } 1318 1319 if (OCS_LOG_ENABLE_SCSI_TRACE(ocs)) { 1320 ocs_log_sgl(io); 1321 } 1322 1323 if (io->app_id) { 1324 io->iparam.fcp_tgt.app_id = io->app_id; 1325 } 1326 1327 rc = ocs_hw_io_send(&io->ocs->hw, io->hio_type, io->hio, io->wire_len, &io->iparam, &io->node->rnode, 1328 io->hw_cb, io); 1329 break; 1330 } 1331 case OCS_IO_TYPE_ELS: 1332 case OCS_IO_TYPE_CT: { 1333 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio, 1334 &io->els_req, io->wire_len, 1335 &io->els_rsp, &io->node->rnode, &io->iparam, 1336 io->hw_cb, io); 1337 break; 1338 } 1339 case OCS_IO_TYPE_CT_RESP: { 1340 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio, 1341 &io->els_rsp, io->wire_len, 1342 NULL, &io->node->rnode, &io->iparam, 1343 io->hw_cb, io); 1344 break; 1345 } 1346 case OCS_IO_TYPE_BLS_RESP: { 1347 /* no need to update tgt_task_tag for BLS response since the RX_ID 1348 * will be specified by the payload, not the XRI */ 1349 rc = ocs_hw_srrs_send(&ocs->hw, io->hio_type, io->hio, 1350 NULL, 0, NULL, &io->node->rnode, &io->iparam, io->hw_cb, io); 1351 break; 1352 } 1353 default: 1354 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type); 1355 rc = -1; 1356 break; 1357 } 1358 return rc; 1359 } 1360 1361 /** 1362 * @brief Dispatch IO 1363 * 1364 * @par Description 1365 * An IO that does require a HW IO is dispatched to the HW. 1366 * 1367 * @param io Pointer to IO structure. 1368 * 1369 * @return Returns 0 on success, or a negative error code value on failure. 1370 */ 1371 1372 static int32_t 1373 ocs_scsi_io_dispatch_no_hw_io(ocs_io_t *io) 1374 { 1375 int32_t rc; 1376 1377 switch (io->io_type) { 1378 case OCS_IO_TYPE_ABORT: { 1379 ocs_hw_io_t *hio_to_abort = NULL; 1380 ocs_assert(io->io_to_abort, -1); 1381 hio_to_abort = io->io_to_abort->hio; 1382 1383 if (hio_to_abort == NULL) { 1384 /* 1385 * If "IO to abort" does not have an associated HW IO, immediately 1386 * make callback with success. The command must have been sent to 1387 * the backend, but the data phase has not yet started, so we don't 1388 * have a HW IO. 1389 * 1390 * Note: since the backend shims should be taking a reference 1391 * on io_to_abort, it should not be possible to have been completed 1392 * and freed by the backend before the abort got here. 1393 */ 1394 scsi_io_printf(io, "IO: " SCSI_IOFMT " not active\n", 1395 SCSI_IOFMT_ARGS(io->io_to_abort)); 1396 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, SLI4_FC_WCQE_STATUS_SUCCESS, 0, io); 1397 rc = 0; 1398 } else { 1399 /* HW IO is valid, abort it */ 1400 scsi_io_printf(io, "aborting " SCSI_IOFMT "\n", SCSI_IOFMT_ARGS(io->io_to_abort)); 1401 rc = ocs_hw_io_abort(&io->ocs->hw, hio_to_abort, io->send_abts, 1402 io->hw_cb, io); 1403 if (rc) { 1404 int status = SLI4_FC_WCQE_STATUS_SUCCESS; 1405 if ((rc != OCS_HW_RTN_IO_NOT_ACTIVE) && 1406 (rc != OCS_HW_RTN_IO_ABORT_IN_PROGRESS)) { 1407 status = -1; 1408 scsi_io_printf(io, "Failed to abort IO: " SCSI_IOFMT " status=%d\n", 1409 SCSI_IOFMT_ARGS(io->io_to_abort), rc); 1410 } 1411 ((ocs_hw_done_t)io->hw_cb)(io->hio, NULL, 0, status, 0, io); 1412 rc = 0; 1413 } 1414 } 1415 1416 break; 1417 } 1418 default: 1419 scsi_io_printf(io, "Unknown IO type=%d\n", io->io_type); 1420 rc = -1; 1421 break; 1422 } 1423 return rc; 1424 } 1425 1426 /** 1427 * @ingroup scsi_api_base 1428 * @brief Send read/write data. 1429 * 1430 * @par Description 1431 * This call is made by a target-server to initiate a SCSI read or write data phase, transferring 1432 * data between the target to the remote initiator. The payload is specified by the 1433 * scatter-gather list @c sgl of length @c sgl_count. The @c wire_len argument 1434 * specifies the payload length (independent of the scatter-gather list cumulative length). 1435 * @n @n 1436 * The @c flags argument has one bit, OCS_SCSI_LAST_DATAPHASE, which is a hint to the base 1437 * driver that it may use auto SCSI response features if the hardware supports it. 1438 * @n @n 1439 * Upon completion, the callback function @b cb is called with flags indicating that the 1440 * IO has completed (OCS_SCSI_IO_COMPL) and another data phase or response may be sent; 1441 * that the IO has completed and no response needs to be sent (OCS_SCSI_IO_COMPL_NO_RSP); 1442 * or that the IO was aborted (OCS_SCSI_IO_ABORTED). 1443 * 1444 * @param io Pointer to the IO context. 1445 * @param flags Flags controlling the sending of data. 1446 * @param dif_info Pointer to T10 DIF fields, or NULL if no DIF. 1447 * @param sgl Pointer to the payload scatter-gather list. 1448 * @param sgl_count Count of the scatter-gather list elements. 1449 * @param xwire_len Length of the payload on wire, in bytes. 1450 * @param type HW IO type. 1451 * @param enable_ar Enable auto-response if true. 1452 * @param cb Completion callback. 1453 * @param arg Application-supplied callback data. 1454 * 1455 * @return Returns 0 on success, or a negative error code value on failure. 1456 */ 1457 1458 static inline int32_t 1459 ocs_scsi_xfer_data(ocs_io_t *io, uint32_t flags, 1460 ocs_scsi_dif_info_t *dif_info, 1461 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t xwire_len, 1462 ocs_hw_io_type_e type, int enable_ar, 1463 ocs_scsi_io_cb_t cb, void *arg) 1464 { 1465 int32_t rc; 1466 ocs_t *ocs; 1467 uint32_t disable_ar_tgt_dif = FALSE; 1468 size_t residual = 0; 1469 1470 if ((dif_info != NULL) && (dif_info->dif_oper == OCS_SCSI_DIF_OPER_DISABLED)) { 1471 dif_info = NULL; 1472 } 1473 1474 ocs_assert(io, -1); 1475 1476 if (dif_info != NULL) { 1477 ocs_hw_get(&io->ocs->hw, OCS_HW_DISABLE_AR_TGT_DIF, &disable_ar_tgt_dif); 1478 if (disable_ar_tgt_dif) { 1479 enable_ar = FALSE; 1480 } 1481 } 1482 1483 io->sgl_count = sgl_count; 1484 1485 /* If needed, copy SGL */ 1486 if (sgl && (sgl != io->sgl)) { 1487 ocs_assert(sgl_count <= io->sgl_allocated, -1); 1488 ocs_memcpy(io->sgl, sgl, sgl_count*sizeof(*io->sgl)); 1489 } 1490 1491 ocs = io->ocs; 1492 ocs_assert(ocs, -1); 1493 ocs_assert(io->node, -1); 1494 1495 scsi_io_trace(io, "%s wire_len %d\n", (type == OCS_HW_IO_TARGET_READ) ? "send" : "recv", xwire_len); 1496 1497 ocs_assert(sgl, -1); 1498 ocs_assert(sgl_count > 0, -1); 1499 ocs_assert(io->exp_xfer_len > io->transferred, -1); 1500 1501 io->hio_type = type; 1502 1503 io->scsi_tgt_cb = cb; 1504 io->scsi_tgt_cb_arg = arg; 1505 1506 rc = ocs_scsi_convert_dif_info(ocs, dif_info, &io->hw_dif); 1507 if (rc) { 1508 return rc; 1509 } 1510 1511 /* If DIF is used, then save lba for error recovery */ 1512 if (dif_info) { 1513 io->scsi_dif_info = *dif_info; 1514 } 1515 1516 io->wire_len = MIN(xwire_len, io->exp_xfer_len - io->transferred); 1517 residual = (xwire_len - io->wire_len); 1518 1519 ocs_memset(&io->iparam, 0, sizeof(io->iparam)); 1520 io->iparam.fcp_tgt.ox_id = io->init_task_tag; 1521 io->iparam.fcp_tgt.offset = io->transferred; 1522 io->iparam.fcp_tgt.dif_oper = io->hw_dif.dif; 1523 io->iparam.fcp_tgt.blk_size = io->hw_dif.blk_size; 1524 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl; 1525 io->iparam.fcp_tgt.timeout = io->timeout; 1526 1527 /* if this is the last data phase and there is no residual, enable 1528 * auto-good-response 1529 */ 1530 if (enable_ar && (flags & OCS_SCSI_LAST_DATAPHASE) && 1531 (residual == 0) && ((io->transferred + io->wire_len) == io->exp_xfer_len) && (!(flags & OCS_SCSI_NO_AUTO_RESPONSE))) { 1532 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE; 1533 io->auto_resp = TRUE; 1534 } else { 1535 io->auto_resp = FALSE; 1536 } 1537 1538 /* save this transfer length */ 1539 io->xfer_req = io->wire_len; 1540 1541 /* Adjust the transferred count to account for overrun 1542 * when the residual is calculated in ocs_scsi_send_resp 1543 */ 1544 io->transferred += residual; 1545 1546 /* Adjust the SGL size if there is overrun */ 1547 1548 if (residual) { 1549 ocs_scsi_sgl_t *sgl_ptr = &io->sgl[sgl_count-1]; 1550 1551 while (residual) { 1552 size_t len = sgl_ptr->len; 1553 if ( len > residual) { 1554 sgl_ptr->len = len - residual; 1555 residual = 0; 1556 } else { 1557 sgl_ptr->len = 0; 1558 residual -= len; 1559 io->sgl_count--; 1560 } 1561 sgl_ptr--; 1562 } 1563 } 1564 1565 /* Set latency and WQ steering */ 1566 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0; 1567 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT; 1568 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT; 1569 1570 return ocs_scsi_io_dispatch(io, ocs_target_io_cb); 1571 } 1572 1573 int32_t 1574 ocs_scsi_send_rd_data(ocs_io_t *io, uint32_t flags, 1575 ocs_scsi_dif_info_t *dif_info, 1576 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, 1577 ocs_scsi_io_cb_t cb, void *arg) 1578 { 1579 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_READ, 1580 enable_tsend_auto_resp(io->ocs), cb, arg); 1581 } 1582 1583 int32_t 1584 ocs_scsi_recv_wr_data(ocs_io_t *io, uint32_t flags, 1585 ocs_scsi_dif_info_t *dif_info, 1586 ocs_scsi_sgl_t *sgl, uint32_t sgl_count, uint32_t len, 1587 ocs_scsi_io_cb_t cb, void *arg) 1588 { 1589 return ocs_scsi_xfer_data(io, flags, dif_info, sgl, sgl_count, len, OCS_HW_IO_TARGET_WRITE, 1590 enable_treceive_auto_resp(io->ocs), cb, arg); 1591 } 1592 1593 /** 1594 * @ingroup scsi_api_base 1595 * @brief Free overflow SGL. 1596 * 1597 * @par Description 1598 * Free the overflow SGL if it is present. 1599 * 1600 * @param io Pointer to IO object. 1601 * 1602 * @return None. 1603 */ 1604 static void 1605 ocs_scsi_io_free_ovfl(ocs_io_t *io) { 1606 if (io->ovfl_sgl.size) { 1607 ocs_dma_free(io->ocs, &io->ovfl_sgl); 1608 } 1609 } 1610 1611 /** 1612 * @ingroup scsi_api_base 1613 * @brief Send response data. 1614 * 1615 * @par Description 1616 * This function is used by a target-server to send the SCSI response data to a remote 1617 * initiator node. The target-server populates the @c ocs_scsi_cmd_resp_t 1618 * argument with scsi status, status qualifier, sense data, and response data, as 1619 * needed. 1620 * @n @n 1621 * Upon completion, the callback function @c cb is invoked. The target-server will generally 1622 * clean up its IO context resources and call ocs_scsi_io_complete(). 1623 * 1624 * @param io Pointer to the IO context. 1625 * @param flags Flags to control sending of the SCSI response. 1626 * @param rsp Pointer to the response data populated by the caller. 1627 * @param cb Completion callback. 1628 * @param arg Application-specified completion callback argument. 1629 1630 * @return Returns 0 on success, or a negative error code value on failure. 1631 */ 1632 int32_t 1633 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) 1634 { 1635 ocs_t *ocs; 1636 int32_t residual; 1637 int auto_resp = TRUE; /* Always try auto resp */ 1638 uint8_t scsi_status = 0; 1639 uint16_t scsi_status_qualifier = 0; 1640 uint8_t *sense_data = NULL; 1641 uint32_t sense_data_length = 0; 1642 1643 ocs_assert(io, -1); 1644 1645 ocs = io->ocs; 1646 ocs_assert(ocs, -1); 1647 1648 ocs_assert(io->node, -1); 1649 1650 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif); 1651 1652 if (rsp) { 1653 scsi_status = rsp->scsi_status; 1654 scsi_status_qualifier = rsp->scsi_status_qualifier; 1655 sense_data = rsp->sense_data; 1656 sense_data_length = rsp->sense_data_length; 1657 residual = rsp->residual; 1658 } else { 1659 residual = io->exp_xfer_len - io->transferred; 1660 } 1661 1662 io->wire_len = 0; 1663 io->hio_type = OCS_HW_IO_TARGET_RSP; 1664 1665 io->scsi_tgt_cb = cb; 1666 io->scsi_tgt_cb_arg = arg; 1667 1668 ocs_memset(&io->iparam, 0, sizeof(io->iparam)); 1669 io->iparam.fcp_tgt.ox_id = io->init_task_tag; 1670 io->iparam.fcp_tgt.offset = 0; 1671 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl; 1672 io->iparam.fcp_tgt.timeout = io->timeout; 1673 1674 /* Set low latency queueing request */ 1675 io->low_latency = (flags & OCS_SCSI_LOW_LATENCY) != 0; 1676 io->wq_steering = (flags & OCS_SCSI_WQ_STEERING_MASK) >> OCS_SCSI_WQ_STEERING_SHIFT; 1677 io->wq_class = (flags & OCS_SCSI_WQ_CLASS_MASK) >> OCS_SCSI_WQ_CLASS_SHIFT; 1678 1679 if ((scsi_status != 0) || residual || sense_data_length) { 1680 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt; 1681 1682 if (!fcprsp) { 1683 ocs_log_err(ocs, "NULL response buffer\n"); 1684 return -1; 1685 } 1686 1687 auto_resp = FALSE; 1688 1689 ocs_memset(fcprsp, 0, sizeof(*fcprsp)); 1690 1691 io->wire_len += (sizeof(*fcprsp) - sizeof(fcprsp->data)); 1692 1693 fcprsp->scsi_status = scsi_status; 1694 *((uint16_t*)fcprsp->status_qualifier) = ocs_htobe16(scsi_status_qualifier); 1695 1696 /* set residual status if necessary */ 1697 if (residual != 0) { 1698 /* FCP: if data transferred is less than the amount expected, then this is an 1699 * underflow. If data transferred would have been greater than the amount expected 1700 * then this is an overflow 1701 */ 1702 if (residual > 0) { 1703 fcprsp->flags |= FCP_RESID_UNDER; 1704 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(residual); 1705 } else { 1706 fcprsp->flags |= FCP_RESID_OVER; 1707 *((uint32_t *)fcprsp->fcp_resid) = ocs_htobe32(-residual); 1708 } 1709 } 1710 1711 if (sense_data && sense_data_length) { 1712 ocs_assert(sense_data_length <= sizeof(fcprsp->data), -1); 1713 fcprsp->flags |= FCP_SNS_LEN_VALID; 1714 ocs_memcpy(fcprsp->data, sense_data, sense_data_length); 1715 *((uint32_t*)fcprsp->fcp_sns_len) = ocs_htobe32(sense_data_length); 1716 io->wire_len += sense_data_length; 1717 } 1718 1719 io->sgl[0].addr = io->rspbuf.phys; 1720 io->sgl[0].dif_addr = 0; 1721 io->sgl[0].len = io->wire_len; 1722 io->sgl_count = 1; 1723 } 1724 1725 if (auto_resp) { 1726 io->iparam.fcp_tgt.flags |= SLI4_IO_AUTO_GOOD_RESPONSE; 1727 } 1728 1729 return ocs_scsi_io_dispatch(io, ocs_target_io_cb); 1730 } 1731 1732 /** 1733 * @ingroup scsi_api_base 1734 * @brief Send TMF response data. 1735 * 1736 * @par Description 1737 * This function is used by a target-server to send SCSI TMF response data to a remote 1738 * initiator node. 1739 * Upon completion, the callback function @c cb is invoked. The target-server will generally 1740 * clean up its IO context resources and call ocs_scsi_io_complete(). 1741 * 1742 * @param io Pointer to the IO context. 1743 * @param rspcode TMF response code. 1744 * @param addl_rsp_info Additional TMF response information (may be NULL for zero data). 1745 * @param cb Completion callback. 1746 * @param arg Application-specified completion callback argument. 1747 * 1748 * @return Returns 0 on success, or a negative error code value on failure. 1749 */ 1750 int32_t 1751 ocs_scsi_send_tmf_resp(ocs_io_t *io, ocs_scsi_tmf_resp_e rspcode, uint8_t addl_rsp_info[3], 1752 ocs_scsi_io_cb_t cb, void *arg) 1753 { 1754 int32_t rc = -1; 1755 ocs_t *ocs = NULL; 1756 fcp_rsp_iu_t *fcprsp = NULL; 1757 fcp_rsp_info_t *rspinfo = NULL; 1758 uint8_t fcp_rspcode; 1759 1760 ocs_assert(io, -1); 1761 ocs_assert(io->ocs, -1); 1762 ocs_assert(io->node, -1); 1763 1764 ocs = io->ocs; 1765 1766 io->wire_len = 0; 1767 ocs_scsi_convert_dif_info(ocs, NULL, &io->hw_dif); 1768 1769 switch(rspcode) { 1770 case OCS_SCSI_TMF_FUNCTION_COMPLETE: 1771 fcp_rspcode = FCP_TMF_COMPLETE; 1772 break; 1773 case OCS_SCSI_TMF_FUNCTION_SUCCEEDED: 1774 case OCS_SCSI_TMF_FUNCTION_IO_NOT_FOUND: 1775 fcp_rspcode = FCP_TMF_SUCCEEDED; 1776 break; 1777 case OCS_SCSI_TMF_FUNCTION_REJECTED: 1778 fcp_rspcode = FCP_TMF_REJECTED; 1779 break; 1780 case OCS_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER: 1781 fcp_rspcode = FCP_TMF_INCORRECT_LUN; 1782 break; 1783 case OCS_SCSI_TMF_SERVICE_DELIVERY: 1784 fcp_rspcode = FCP_TMF_FAILED; 1785 break; 1786 default: 1787 fcp_rspcode = FCP_TMF_REJECTED; 1788 break; 1789 } 1790 1791 io->hio_type = OCS_HW_IO_TARGET_RSP; 1792 1793 io->scsi_tgt_cb = cb; 1794 io->scsi_tgt_cb_arg = arg; 1795 1796 if (io->tmf_cmd == OCS_SCSI_TMF_ABORT_TASK) { 1797 rc = ocs_target_send_bls_resp(io, cb, arg); 1798 return rc; 1799 } 1800 1801 /* populate the FCP TMF response */ 1802 fcprsp = io->rspbuf.virt; 1803 ocs_memset(fcprsp, 0, sizeof(*fcprsp)); 1804 1805 fcprsp->flags |= FCP_RSP_LEN_VALID; 1806 1807 rspinfo = (fcp_rsp_info_t*) fcprsp->data; 1808 if (addl_rsp_info != NULL) { 1809 ocs_memcpy(rspinfo->addl_rsp_info, addl_rsp_info, sizeof(rspinfo->addl_rsp_info)); 1810 } 1811 rspinfo->rsp_code = fcp_rspcode; 1812 1813 io->wire_len = sizeof(*fcprsp) - sizeof(fcprsp->data) + sizeof(*rspinfo); 1814 1815 *((uint32_t*)fcprsp->fcp_rsp_len) = ocs_htobe32(sizeof(*rspinfo)); 1816 1817 io->sgl[0].addr = io->rspbuf.phys; 1818 io->sgl[0].dif_addr = 0; 1819 io->sgl[0].len = io->wire_len; 1820 io->sgl_count = 1; 1821 1822 ocs_memset(&io->iparam, 0, sizeof(io->iparam)); 1823 io->iparam.fcp_tgt.ox_id = io->init_task_tag; 1824 io->iparam.fcp_tgt.offset = 0; 1825 io->iparam.fcp_tgt.cs_ctl = io->cs_ctl; 1826 io->iparam.fcp_tgt.timeout = io->timeout; 1827 1828 rc = ocs_scsi_io_dispatch(io, ocs_target_io_cb); 1829 1830 return rc; 1831 } 1832 1833 /** 1834 * @brief Process target abort callback. 1835 * 1836 * @par Description 1837 * Accepts HW abort requests. 1838 * 1839 * @param hio HW IO context. 1840 * @param rnode Remote node. 1841 * @param length Length of response data. 1842 * @param status Completion status. 1843 * @param ext_status Extended completion status. 1844 * @param app Application-specified callback data. 1845 * 1846 * @return Returns 0 on success, or a negative error code value on failure. 1847 */ 1848 1849 static int32_t 1850 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) 1851 { 1852 ocs_io_t *io = app; 1853 ocs_t *ocs; 1854 ocs_scsi_io_status_e scsi_status; 1855 1856 ocs_assert(io, -1); 1857 ocs_assert(io->ocs, -1); 1858 1859 ocs = io->ocs; 1860 1861 if (io->abort_cb) { 1862 ocs_scsi_io_cb_t abort_cb = io->abort_cb; 1863 void *abort_cb_arg = io->abort_cb_arg; 1864 1865 io->abort_cb = NULL; 1866 io->abort_cb_arg = NULL; 1867 1868 switch (status) { 1869 case SLI4_FC_WCQE_STATUS_SUCCESS: 1870 scsi_status = OCS_SCSI_STATUS_GOOD; 1871 break; 1872 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT: 1873 switch (ext_status) { 1874 case SLI4_FC_LOCAL_REJECT_NO_XRI: 1875 scsi_status = OCS_SCSI_STATUS_NO_IO; 1876 break; 1877 case SLI4_FC_LOCAL_REJECT_ABORT_IN_PROGRESS: 1878 scsi_status = OCS_SCSI_STATUS_ABORT_IN_PROGRESS; 1879 break; 1880 default: 1881 /* TODO: we have seen 0x15 (abort in progress) */ 1882 scsi_status = OCS_SCSI_STATUS_ERROR; 1883 break; 1884 } 1885 break; 1886 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE: 1887 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE; 1888 break; 1889 default: 1890 scsi_status = OCS_SCSI_STATUS_ERROR; 1891 break; 1892 } 1893 /* invoke callback */ 1894 abort_cb(io->io_to_abort, scsi_status, 0, abort_cb_arg); 1895 } 1896 1897 ocs_assert(io != io->io_to_abort, -1); 1898 1899 /* done with IO to abort */ 1900 ocs_ref_put(&io->io_to_abort->ref); /* ocs_ref_get(): ocs_scsi_tgt_abort_io() */ 1901 1902 ocs_io_free(ocs, io); 1903 1904 ocs_scsi_check_pending(ocs); 1905 return 0; 1906 } 1907 1908 /** 1909 * @ingroup scsi_api_base 1910 * @brief Abort a target IO. 1911 * 1912 * @par Description 1913 * This routine is called from a SCSI target-server. It initiates an abort of a 1914 * previously-issued target data phase or response request. 1915 * 1916 * @param io IO context. 1917 * @param cb SCSI target server callback. 1918 * @param arg SCSI target server supplied callback argument. 1919 * 1920 * @return Returns 0 on success, or a non-zero value on failure. 1921 */ 1922 int32_t 1923 ocs_scsi_tgt_abort_io(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg) 1924 { 1925 ocs_t *ocs; 1926 ocs_xport_t *xport; 1927 int32_t rc; 1928 1929 ocs_io_t *abort_io = NULL; 1930 ocs_assert(io, -1); 1931 ocs_assert(io->node, -1); 1932 ocs_assert(io->ocs, -1); 1933 1934 ocs = io->ocs; 1935 xport = ocs->xport; 1936 1937 /* take a reference on IO being aborted */ 1938 if ((ocs_ref_get_unless_zero(&io->ref) == 0)) { 1939 /* command no longer active */ 1940 scsi_io_printf(io, "command no longer active\n"); 1941 return -1; 1942 } 1943 1944 /* 1945 * allocate a new IO to send the abort request. Use ocs_io_alloc() directly, as 1946 * we need an IO object that will not fail allocation due to allocations being 1947 * disabled (in ocs_scsi_io_alloc()) 1948 */ 1949 abort_io = ocs_io_alloc(ocs); 1950 if (abort_io == NULL) { 1951 ocs_atomic_add_return(&xport->io_alloc_failed_count, 1); 1952 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */ 1953 return -1; 1954 } 1955 1956 /* Save the target server callback and argument */ 1957 ocs_assert(abort_io->hio == NULL, -1); 1958 1959 /* set generic fields */ 1960 abort_io->cmd_tgt = TRUE; 1961 abort_io->node = io->node; 1962 1963 /* set type and abort-specific fields */ 1964 abort_io->io_type = OCS_IO_TYPE_ABORT; 1965 abort_io->display_name = "tgt_abort"; 1966 abort_io->io_to_abort = io; 1967 abort_io->send_abts = FALSE; 1968 abort_io->abort_cb = cb; 1969 abort_io->abort_cb_arg = arg; 1970 1971 /* now dispatch IO */ 1972 rc = ocs_scsi_io_dispatch_abort(abort_io, ocs_target_abort_cb); 1973 if (rc) { 1974 ocs_ref_put(&io->ref); /* ocs_ref_get(): same function */ 1975 } 1976 return rc; 1977 } 1978 1979 /** 1980 * @brief Process target BLS response callback. 1981 * 1982 * @par Description 1983 * Accepts HW abort requests. 1984 * 1985 * @param hio HW IO context. 1986 * @param rnode Remote node. 1987 * @param length Length of response data. 1988 * @param status Completion status. 1989 * @param ext_status Extended completion status. 1990 * @param app Application-specified callback data. 1991 * 1992 * @return Returns 0 on success, or a negative error code value on failure. 1993 */ 1994 1995 static int32_t 1996 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) 1997 { 1998 ocs_io_t *io = app; 1999 ocs_t *ocs; 2000 ocs_scsi_io_status_e bls_status; 2001 2002 ocs_assert(io, -1); 2003 ocs_assert(io->ocs, -1); 2004 2005 ocs = io->ocs; 2006 2007 /* BLS isn't really a "SCSI" concept, but use SCSI status */ 2008 if (status) { 2009 io_error_log(io, "s=%#x x=%#x\n", status, ext_status); 2010 bls_status = OCS_SCSI_STATUS_ERROR; 2011 } else { 2012 bls_status = OCS_SCSI_STATUS_GOOD; 2013 } 2014 2015 if (io->bls_cb) { 2016 ocs_scsi_io_cb_t bls_cb = io->bls_cb; 2017 void *bls_cb_arg = io->bls_cb_arg; 2018 2019 io->bls_cb = NULL; 2020 io->bls_cb_arg = NULL; 2021 2022 /* invoke callback */ 2023 bls_cb(io, bls_status, 0, bls_cb_arg); 2024 } 2025 2026 ocs_scsi_check_pending(ocs); 2027 return 0; 2028 } 2029 2030 /** 2031 * @brief Complete abort request. 2032 * 2033 * @par Description 2034 * An abort request is completed by posting a BA_ACC for the IO that requested the abort. 2035 * 2036 * @param io Pointer to the IO context. 2037 * @param cb Callback function to invoke upon completion. 2038 * @param arg Application-specified completion callback argument. 2039 * 2040 * @return Returns 0 on success, or a negative error code value on failure. 2041 */ 2042 2043 static int32_t 2044 ocs_target_send_bls_resp(ocs_io_t *io, ocs_scsi_io_cb_t cb, void *arg) 2045 { 2046 int32_t rc; 2047 fc_ba_acc_payload_t *acc; 2048 2049 ocs_assert(io, -1); 2050 2051 /* fill out IO structure with everything needed to send BA_ACC */ 2052 ocs_memset(&io->iparam, 0, sizeof(io->iparam)); 2053 io->iparam.bls.ox_id = io->init_task_tag; 2054 io->iparam.bls.rx_id = io->abort_rx_id; 2055 2056 acc = (void *)io->iparam.bls.payload; 2057 2058 ocs_memset(io->iparam.bls.payload, 0, sizeof(io->iparam.bls.payload)); 2059 acc->ox_id = io->iparam.bls.ox_id; 2060 acc->rx_id = io->iparam.bls.rx_id; 2061 acc->high_seq_cnt = UINT16_MAX; 2062 2063 /* generic io fields have already been populated */ 2064 2065 /* set type and BLS-specific fields */ 2066 io->io_type = OCS_IO_TYPE_BLS_RESP; 2067 io->display_name = "bls_rsp"; 2068 io->hio_type = OCS_HW_BLS_ACC; 2069 io->bls_cb = cb; 2070 io->bls_cb_arg = arg; 2071 2072 /* dispatch IO */ 2073 rc = ocs_scsi_io_dispatch(io, ocs_target_bls_resp_cb); 2074 return rc; 2075 } 2076 2077 /** 2078 * @ingroup scsi_api_base 2079 * @brief Notify the base driver that the IO is complete. 2080 * 2081 * @par Description 2082 * This function is called by a target-server to notify the base driver that an IO 2083 * has completed, allowing for the base driver to free resources. 2084 * @n 2085 * @n @b Note: This function is not called by initiator-clients. 2086 * 2087 * @param io Pointer to IO context. 2088 * 2089 * @return None. 2090 */ 2091 void 2092 ocs_scsi_io_complete(ocs_io_t *io) 2093 { 2094 ocs_assert(io); 2095 2096 if (!ocs_io_busy(io)) { 2097 ocs_log_test(io->ocs, "Got completion for non-busy io with tag 0x%x\n", io->tag); 2098 return; 2099 } 2100 2101 scsi_io_trace(io, "freeing io 0x%p %s\n", io, io->display_name); 2102 ocs_assert(ocs_ref_read_count(&io->ref) > 0); 2103 ocs_ref_put(&io->ref); /* ocs_ref_get(): ocs_scsi_io_alloc() */ 2104 } 2105 2106 /** 2107 * @brief Handle initiator IO completion. 2108 * 2109 * @par Description 2110 * This callback is made upon completion of an initiator operation (initiator read/write command). 2111 * 2112 * @param hio HW IO context. 2113 * @param rnode Remote node. 2114 * @param length Length of completion data. 2115 * @param status Completion status. 2116 * @param ext_status Extended completion status. 2117 * @param app Application-specified callback data. 2118 * 2119 * @return None. 2120 */ 2121 2122 static void 2123 ocs_initiator_io_cb(ocs_hw_io_t *hio, ocs_remote_node_t *rnode, uint32_t length, 2124 int32_t status, uint32_t ext_status, void *app) 2125 { 2126 ocs_io_t *io = app; 2127 ocs_t *ocs; 2128 ocs_scsi_io_status_e scsi_status; 2129 2130 ocs_assert(io); 2131 ocs_assert(io->scsi_ini_cb); 2132 2133 scsi_io_trace(io, "status x%x ext_status x%x\n", status, ext_status); 2134 2135 ocs = io->ocs; 2136 ocs_assert(ocs); 2137 2138 ocs_scsi_io_free_ovfl(io); 2139 2140 /* Call target server completion */ 2141 if (io->scsi_ini_cb) { 2142 fcp_rsp_iu_t *fcprsp = io->rspbuf.virt; 2143 ocs_scsi_cmd_resp_t rsp; 2144 ocs_scsi_rsp_io_cb_t cb = io->scsi_ini_cb; 2145 uint32_t flags = 0; 2146 uint8_t *pd = fcprsp->data; 2147 2148 /* Clear the callback before invoking the callback */ 2149 io->scsi_ini_cb = NULL; 2150 2151 ocs_memset(&rsp, 0, sizeof(rsp)); 2152 2153 /* Unless status is FCP_RSP_FAILURE, fcprsp is not filled in */ 2154 switch (status) { 2155 case SLI4_FC_WCQE_STATUS_SUCCESS: 2156 scsi_status = OCS_SCSI_STATUS_GOOD; 2157 break; 2158 case SLI4_FC_WCQE_STATUS_FCP_RSP_FAILURE: 2159 scsi_status = OCS_SCSI_STATUS_CHECK_RESPONSE; 2160 rsp.scsi_status = fcprsp->scsi_status; 2161 rsp.scsi_status_qualifier = ocs_be16toh(*((uint16_t*)fcprsp->status_qualifier)); 2162 2163 if (fcprsp->flags & FCP_RSP_LEN_VALID) { 2164 rsp.response_data = pd; 2165 rsp.response_data_length = ocs_fc_getbe32(fcprsp->fcp_rsp_len); 2166 pd += rsp.response_data_length; 2167 } 2168 if (fcprsp->flags & FCP_SNS_LEN_VALID) { 2169 uint32_t sns_len = ocs_fc_getbe32(fcprsp->fcp_sns_len); 2170 rsp.sense_data = pd; 2171 rsp.sense_data_length = sns_len; 2172 pd += sns_len; 2173 } 2174 /* Set residual */ 2175 if (fcprsp->flags & FCP_RESID_OVER) { 2176 rsp.residual = -ocs_fc_getbe32(fcprsp->fcp_resid); 2177 rsp.response_wire_length = length; 2178 } else if (fcprsp->flags & FCP_RESID_UNDER) { 2179 rsp.residual = ocs_fc_getbe32(fcprsp->fcp_resid); 2180 rsp.response_wire_length = length; 2181 } 2182 2183 /* 2184 * Note: The FCP_RSP_FAILURE can be returned for initiator IOs when the total data 2185 * placed does not match the requested length even if the status is good. If 2186 * the status is all zeroes, then we have to assume that a frame(s) were 2187 * dropped and change the status to LOCAL_REJECT/OUT_OF_ORDER_DATA 2188 */ 2189 if (length != io->wire_len) { 2190 uint32_t rsp_len = ext_status; 2191 uint8_t *rsp_bytes = io->rspbuf.virt; 2192 uint32_t i; 2193 uint8_t all_zeroes = (rsp_len > 0); 2194 /* Check if the rsp is zero */ 2195 for (i = 0; i < rsp_len; i++) { 2196 if (rsp_bytes[i] != 0) { 2197 all_zeroes = FALSE; 2198 break; 2199 } 2200 } 2201 if (all_zeroes) { 2202 scsi_status = OCS_SCSI_STATUS_ERROR; 2203 ocs_log_test(io->ocs, "[%s]" SCSI_IOFMT "local reject=0x%02x\n", 2204 io->node->display_name, SCSI_IOFMT_ARGS(io), 2205 SLI4_FC_LOCAL_REJECT_OUT_OF_ORDER_DATA); 2206 } 2207 } 2208 break; 2209 case SLI4_FC_WCQE_STATUS_LOCAL_REJECT: 2210 if (ext_status == SLI4_FC_LOCAL_REJECT_SEQUENCE_TIMEOUT) { 2211 scsi_status = OCS_SCSI_STATUS_COMMAND_TIMEOUT; 2212 } else { 2213 scsi_status = OCS_SCSI_STATUS_ERROR; 2214 } 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 #if defined(OCS_ENABLE_VPD_SUPPORT) 2812 case OCS_SCSI_SERIALNUMBER: 2813 { 2814 uint8_t *pvpd; 2815 uint32_t vpd_len; 2816 2817 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) { 2818 ocs_log_test(ocs, "Can't get VPD length\n"); 2819 rc = "\012sn-unknown"; 2820 break; 2821 } 2822 2823 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD); 2824 if (pvpd) { 2825 rc = ocs_find_vpd(pvpd, vpd_len, "SN"); 2826 } 2827 2828 if (rc == NULL || 2829 ocs_strlen(rc) == 0) { 2830 /* Note: VPD is missing, using wwnn for serial number */ 2831 scsi_log(ocs, "Note: VPD is missing, using wwnn for serial number\n"); 2832 /* Use the last 32 bits of the WWN */ 2833 if ((ocs == NULL) || (ocs->domain == NULL) || (ocs->domain->sport == NULL)) { 2834 rc = "\011(Unknown)"; 2835 } else { 2836 rc = &ocs->domain->sport->wwnn_str[8]; 2837 } 2838 } 2839 break; 2840 } 2841 case OCS_SCSI_PARTNUMBER: 2842 { 2843 uint8_t *pvpd; 2844 uint32_t vpd_len; 2845 2846 if (ocs_hw_get(&ocs->hw, OCS_HW_VPD_LEN, &vpd_len)) { 2847 ocs_log_test(ocs, "Can't get VPD length\n"); 2848 rc = "\012pn-unknown"; 2849 break; 2850 } 2851 pvpd = ocs_hw_get_ptr(&ocs->hw, OCS_HW_VPD); 2852 if (pvpd) { 2853 rc = ocs_find_vpd(pvpd, vpd_len, "PN"); 2854 if (rc == NULL) { 2855 rc = "\012pn-unknown"; 2856 } 2857 } else { 2858 rc = "\012pn-unknown"; 2859 } 2860 break; 2861 } 2862 #endif 2863 default: 2864 break; 2865 } 2866 2867 if (rc == NULL) { 2868 ocs_log_debug(ocs, "invalid property request %d\n", prop); 2869 } 2870 return rc; 2871 } 2872 2873 /** 2874 * @ingroup scsi_api_base 2875 * @brief Notify that delete initiator is complete. 2876 * 2877 * @par Description 2878 * Sent by the target-server to notify the base driver that the work started from 2879 * ocs_scsi_del_initiator() is now complete and that it is safe for the node to 2880 * release the rest of its resources. 2881 * 2882 * @param node Pointer to the node. 2883 * 2884 * @return None. 2885 */ 2886 void 2887 ocs_scsi_del_initiator_complete(ocs_node_t *node) 2888 { 2889 /* Notify the node to resume */ 2890 ocs_node_post_event(node, OCS_EVT_NODE_DEL_INI_COMPLETE, NULL); 2891 } 2892 2893 /** 2894 * @ingroup scsi_api_base 2895 * @brief Notify that delete target is complete. 2896 * 2897 * @par Description 2898 * Sent by the initiator-client to notify the base driver that the work started from 2899 * ocs_scsi_del_target() is now complete and that it is safe for the node to 2900 * release the rest of its resources. 2901 * 2902 * @param node Pointer to the node. 2903 * 2904 * @return None. 2905 */ 2906 void 2907 ocs_scsi_del_target_complete(ocs_node_t *node) 2908 { 2909 /* Notify the node to resume */ 2910 ocs_node_post_event(node, OCS_EVT_NODE_DEL_TGT_COMPLETE, NULL); 2911 } 2912 2913 /** 2914 * @brief Update transferred count 2915 * 2916 * @par Description 2917 * Updates io->transferred, as required when using first burst, when the amount 2918 * of first burst data processed differs from the amount of first burst 2919 * data received. 2920 * 2921 * @param io Pointer to the io object. 2922 * @param transferred Number of bytes transferred out of first burst buffers. 2923 * 2924 * @return None. 2925 */ 2926 void 2927 ocs_scsi_update_first_burst_transferred(ocs_io_t *io, uint32_t transferred) 2928 { 2929 io->transferred = transferred; 2930 } 2931 2932 /** 2933 * @brief Register bounce callback for multi-threading. 2934 * 2935 * @par Description 2936 * Register the back end bounce function. 2937 * 2938 * @param ocs Pointer to device object. 2939 * @param fctn Function pointer of bounce function. 2940 * 2941 * @return None. 2942 */ 2943 void 2944 ocs_scsi_register_bounce(ocs_t *ocs, void(*fctn)(void(*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id, 2945 uint32_t ox_id)) 2946 { 2947 ocs_hw_rtn_e rc; 2948 2949 rc = ocs_hw_callback(&ocs->hw, OCS_HW_CB_BOUNCE, fctn, NULL); 2950 if (rc) { 2951 ocs_log_test(ocs, "ocs_hw_callback(OCS_HW_CB_BOUNCE) failed: %d\n", rc); 2952 } 2953 } 2954