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 * Provide IO object allocation. 37 */ 38 39 /*! 40 * @defgroup io_alloc IO allocation 41 */ 42 43 #include "ocs.h" 44 #include "ocs_scsi.h" 45 #include "ocs_els.h" 46 #include "ocs_utils.h" 47 48 void ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *io); 49 void ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *io); 50 int ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *io); 51 52 static ocs_mgmt_functions_t io_mgmt_functions = { 53 .get_list_handler = ocs_mgmt_io_list, 54 .get_handler = ocs_mgmt_io_get, 55 .get_all_handler = ocs_mgmt_io_get_all, 56 }; 57 58 /** 59 * @brief IO pool. 60 * 61 * Structure encapsulating a pool of IO objects. 62 * 63 */ 64 65 struct ocs_io_pool_s { 66 ocs_t *ocs; /* Pointer to device object */ 67 ocs_lock_t lock; /* IO pool lock */ 68 uint32_t io_num_ios; /* Total IOs allocated */ 69 ocs_pool_t *pool; 70 }; 71 72 /** 73 * @brief Create a pool of IO objects. 74 * 75 * @par Description 76 * This function allocates memory in larger chucks called 77 * "slabs" which are a fixed size. It calculates the number of IO objects that 78 * fit within each "slab" and determines the number of "slabs" required to 79 * allocate the number of IOs requested. Each of the slabs is allocated and 80 * then it grabs each IO object within the slab and adds it to the free list. 81 * Individual command, response and SGL DMA buffers are allocated for each IO. 82 * 83 * "Slabs" 84 * +----------------+ 85 * | | 86 * +----------------+ | 87 * | IO | | 88 * +----------------+ | 89 * | ... | | 90 * +----------------+__+ 91 * | IO | 92 * +----------------+ 93 * 94 * @param ocs Driver instance's software context. 95 * @param num_io Number of IO contexts to allocate. 96 * @param num_sgl Number of SGL entries to allocate for each IO. 97 * 98 * @return Returns a pointer to a new ocs_io_pool_t on success, 99 * or NULL on failure. 100 */ 101 102 ocs_io_pool_t * 103 ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl) 104 { 105 uint32_t i = 0; 106 int32_t rc = -1; 107 ocs_io_pool_t *io_pool; 108 109 /* Allocate the IO pool */ 110 io_pool = ocs_malloc(ocs, sizeof(*io_pool), OCS_M_ZERO | OCS_M_NOWAIT); 111 if (io_pool == NULL) { 112 ocs_log_err(ocs, "allocate of IO pool failed\n"); 113 return NULL;; 114 } 115 116 io_pool->ocs = ocs; 117 io_pool->io_num_ios = num_io; 118 119 /* initialize IO pool lock */ 120 ocs_lock_init(ocs, &io_pool->lock, "io_pool lock[%d]", ocs->instance_index); 121 122 io_pool->pool = ocs_pool_alloc(ocs, sizeof(ocs_io_t), io_pool->io_num_ios, FALSE); 123 124 for (i = 0; i < io_pool->io_num_ios; i++) { 125 ocs_io_t *io = ocs_pool_get_instance(io_pool->pool, i); 126 127 io->tag = i; 128 io->instance_index = i; 129 io->ocs = ocs; 130 131 /* allocate a command/response dma buffer */ 132 if (ocs->enable_ini) { 133 rc = ocs_dma_alloc(ocs, &io->cmdbuf, SCSI_CMD_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT); 134 if (rc) { 135 ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n"); 136 ocs_io_pool_free(io_pool); 137 return NULL; 138 } 139 } 140 141 /* Allocate a response buffer */ 142 rc = ocs_dma_alloc(ocs, &io->rspbuf, SCSI_RSP_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT); 143 if (rc) { 144 ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n"); 145 ocs_io_pool_free(io_pool); 146 return NULL; 147 } 148 149 /* Allocate SGL */ 150 io->sgl = ocs_malloc(ocs, sizeof(*io->sgl) * num_sgl, OCS_M_NOWAIT | OCS_M_ZERO); 151 if (io->sgl == NULL) { 152 ocs_log_err(ocs, "malloc sgl's failed\n"); 153 ocs_io_pool_free(io_pool); 154 return NULL; 155 } 156 io->sgl_allocated = num_sgl; 157 io->sgl_count = 0; 158 159 /* Make IO backend call to initialize IO */ 160 ocs_scsi_tgt_io_init(io); 161 ocs_scsi_ini_io_init(io); 162 163 rc = ocs_dma_alloc(ocs, &io->els_req, OCS_ELS_REQ_LEN, OCS_MIN_DMA_ALIGNMENT); 164 if (rc) { 165 ocs_log_err(ocs, "ocs_dma_alloc els_req failed\n"); 166 ocs_io_pool_free(io_pool); 167 return NULL; 168 } 169 170 rc = ocs_dma_alloc(ocs, &io->els_rsp, OCS_ELS_GID_PT_RSP_LEN, OCS_MIN_DMA_ALIGNMENT); 171 if (rc) { 172 ocs_log_err(ocs, "ocs_dma_alloc els_rsp failed\n"); 173 ocs_io_pool_free(io_pool); 174 return NULL; 175 } 176 } 177 178 return io_pool; 179 } 180 181 /** 182 * @brief Free IO objects pool 183 * 184 * @par Description 185 * The pool of IO objects are freed. 186 * 187 * @param io_pool Pointer to IO pool object. 188 * 189 * @return Returns 0 on success, or a negative error code value on failure. 190 */ 191 int32_t 192 ocs_io_pool_free(ocs_io_pool_t *io_pool) 193 { 194 ocs_t *ocs; 195 uint32_t i; 196 ocs_io_t *io; 197 198 if (io_pool != NULL) { 199 ocs = io_pool->ocs; 200 for (i = 0; i < io_pool->io_num_ios; i++) { 201 io = ocs_pool_get_instance(io_pool->pool, i); 202 if (!io) 203 continue; 204 ocs_scsi_tgt_io_exit(io); 205 ocs_scsi_ini_io_exit(io); 206 if (io->sgl) { 207 ocs_free(ocs, io->sgl, sizeof(*io->sgl) * io->sgl_allocated); 208 } 209 ocs_dma_free(ocs, &io->cmdbuf); 210 ocs_dma_free(ocs, &io->rspbuf); 211 ocs_dma_free(ocs, &io->els_req); 212 ocs_dma_free(ocs, &io->els_rsp); 213 } 214 215 if (io_pool->pool != NULL) { 216 ocs_pool_free(io_pool->pool); 217 } 218 ocs_lock_free(&io_pool->lock); 219 ocs_free(ocs, io_pool, sizeof(*io_pool)); 220 ocs->xport->io_pool = NULL; 221 } 222 223 return 0; 224 } 225 226 uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool) 227 { 228 return io_pool->io_num_ios; 229 } 230 231 /** 232 * @ingroup io_alloc 233 * @brief Allocate an object used to track an IO. 234 * 235 * @param io_pool Pointer to the IO pool. 236 * 237 * @return Returns the pointer to a new object, or NULL if none available. 238 */ 239 ocs_io_t * 240 ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool) 241 { 242 ocs_io_t *io = NULL; 243 ocs_t *ocs; 244 245 ocs_assert(io_pool, NULL); 246 247 ocs = io_pool->ocs; 248 249 ocs_lock(&io_pool->lock); 250 if ((io = ocs_pool_get(io_pool->pool)) != NULL) { 251 ocs_unlock(&io_pool->lock); 252 253 io->io_type = OCS_IO_TYPE_MAX; 254 io->hio_type = OCS_HW_IO_MAX; 255 io->hio = NULL; 256 io->transferred = 0; 257 io->ocs = ocs; 258 io->timeout = 0; 259 io->sgl_count = 0; 260 io->tgt_task_tag = 0; 261 io->init_task_tag = 0; 262 io->hw_tag = 0; 263 io->display_name = "pending"; 264 io->seq_init = 0; 265 io->els_req_free = 0; 266 io->mgmt_functions = &io_mgmt_functions; 267 io->io_free = 0; 268 ocs_atomic_add_return(&ocs->xport->io_active_count, 1); 269 ocs_atomic_add_return(&ocs->xport->io_total_alloc, 1); 270 } else { 271 ocs_unlock(&io_pool->lock); 272 } 273 return io; 274 } 275 276 /** 277 * @ingroup io_alloc 278 * @brief Free an object used to track an IO. 279 * 280 * @param io_pool Pointer to IO pool object. 281 * @param io Pointer to the IO object. 282 */ 283 void 284 ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io) 285 { 286 ocs_t *ocs; 287 ocs_hw_io_t *hio = NULL; 288 289 ocs_assert(io_pool); 290 291 ocs = io_pool->ocs; 292 293 ocs_lock(&io_pool->lock); 294 hio = io->hio; 295 io->hio = NULL; 296 ocs_pool_put(io_pool->pool, io); 297 ocs_unlock(&io_pool->lock); 298 299 if (hio) { 300 ocs_hw_io_free(&ocs->hw, hio); 301 } 302 io->io_free = 1; 303 ocs_atomic_sub_return(&ocs->xport->io_active_count, 1); 304 ocs_atomic_add_return(&ocs->xport->io_total_free, 1); 305 } 306 307 /** 308 * @ingroup io_alloc 309 * @brief Find an I/O given it's node and ox_id. 310 * 311 * @param ocs Driver instance's software context. 312 * @param node Pointer to node. 313 * @param ox_id OX_ID to find. 314 * @param rx_id RX_ID to find (0xffff for unassigned). 315 */ 316 ocs_io_t * 317 ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id) 318 { 319 ocs_io_t *io = NULL; 320 321 ocs_lock(&node->active_ios_lock); 322 ocs_list_foreach(&node->active_ios, io) 323 if ((io->cmd_tgt && (io->init_task_tag == ox_id)) && 324 ((rx_id == 0xffff) || (io->tgt_task_tag == rx_id))) { 325 break; 326 } 327 ocs_unlock(&node->active_ios_lock); 328 return io; 329 } 330 331 /** 332 * @ingroup io_alloc 333 * @brief Return IO context given the instance index. 334 * 335 * @par Description 336 * Returns a pointer to the IO context given by the instance index. 337 * 338 * @param ocs Pointer to driver structure. 339 * @param index IO instance index to return. 340 * 341 * @return Returns a pointer to the IO context, or NULL if not found. 342 */ 343 ocs_io_t * 344 ocs_io_get_instance(ocs_t *ocs, uint32_t index) 345 { 346 ocs_xport_t *xport = ocs->xport; 347 ocs_io_pool_t *io_pool = xport->io_pool; 348 return ocs_pool_get_instance(io_pool->pool, index); 349 } 350 351 /** 352 * @brief Generate IO context ddump data. 353 * 354 * The ddump data for an IO context is generated. 355 * 356 * @param textbuf Pointer to text buffer. 357 * @param io Pointer to IO context. 358 * 359 * @return None. 360 */ 361 362 void 363 ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io) 364 { 365 ocs_ddump_section(textbuf, "io", io->instance_index); 366 ocs_ddump_value(textbuf, "display_name", "%s", io->display_name); 367 ocs_ddump_value(textbuf, "node_name", "%s", io->node->display_name); 368 369 ocs_ddump_value(textbuf, "ref_count", "%d", ocs_ref_read_count(&io->ref)); 370 ocs_ddump_value(textbuf, "io_type", "%d", io->io_type); 371 ocs_ddump_value(textbuf, "hio_type", "%d", io->hio_type); 372 ocs_ddump_value(textbuf, "cmd_tgt", "%d", io->cmd_tgt); 373 ocs_ddump_value(textbuf, "cmd_ini", "%d", io->cmd_ini); 374 ocs_ddump_value(textbuf, "send_abts", "%d", io->send_abts); 375 ocs_ddump_value(textbuf, "init_task_tag", "0x%x", io->init_task_tag); 376 ocs_ddump_value(textbuf, "tgt_task_tag", "0x%x", io->tgt_task_tag); 377 ocs_ddump_value(textbuf, "hw_tag", "0x%x", io->hw_tag); 378 ocs_ddump_value(textbuf, "tag", "0x%x", io->tag); 379 ocs_ddump_value(textbuf, "timeout", "%d", io->timeout); 380 ocs_ddump_value(textbuf, "tmf_cmd", "%d", io->tmf_cmd); 381 ocs_ddump_value(textbuf, "abort_rx_id", "0x%x", io->abort_rx_id); 382 383 ocs_ddump_value(textbuf, "busy", "%d", ocs_io_busy(io)); 384 ocs_ddump_value(textbuf, "transferred", "%zu", io->transferred); 385 ocs_ddump_value(textbuf, "auto_resp", "%d", io->auto_resp); 386 ocs_ddump_value(textbuf, "exp_xfer_len", "%d", io->exp_xfer_len); 387 ocs_ddump_value(textbuf, "xfer_req", "%d", io->xfer_req); 388 ocs_ddump_value(textbuf, "seq_init", "%d", io->seq_init); 389 390 ocs_ddump_value(textbuf, "alloc_link", "%d", ocs_list_on_list(&io->io_alloc_link)); 391 ocs_ddump_value(textbuf, "pending_link", "%d", ocs_list_on_list(&io->io_pending_link)); 392 ocs_ddump_value(textbuf, "backend_link", "%d", ocs_list_on_list(&io->link)); 393 394 if (io->hio) { 395 ocs_ddump_value(textbuf, "hw_tag", "%#x", io->hio->reqtag); 396 ocs_ddump_value(textbuf, "hw_xri", "%#x", io->hio->indicator); 397 ocs_ddump_value(textbuf, "hw_type", "%#x", io->hio->type); 398 } else { 399 ocs_ddump_value(textbuf, "hw_tag", "%s", "pending"); 400 ocs_ddump_value(textbuf, "hw_xri", "%s", "pending"); 401 ocs_ddump_value(textbuf, "hw_type", "%s", "pending"); 402 } 403 404 ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_IO, io); 405 ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_IO, io); 406 407 ocs_ddump_endsection(textbuf, "io", io->instance_index); 408 } 409 410 411 void 412 ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *object) 413 { 414 415 /* Readonly values */ 416 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name"); 417 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init_task_tag"); 418 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "tag"); 419 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "transferred"); 420 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "auto_resp"); 421 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "exp_xfer_len"); 422 ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "xfer_req"); 423 } 424 425 int 426 ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object) 427 { 428 char qualifier[80]; 429 int retval = -1; 430 ocs_io_t *io = (ocs_io_t *) object; 431 432 snprintf(qualifier, sizeof(qualifier), "%s/io[%d]", parent, io->instance_index); 433 434 /* If it doesn't start with my qualifier I don't know what to do with it */ 435 if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) { 436 char *unqualified_name = name + strlen(qualifier) +1; 437 438 /* See if it's a value I can supply */ 439 if (ocs_strcmp(unqualified_name, "display_name") == 0) { 440 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name); 441 retval = 0; 442 } else if (ocs_strcmp(unqualified_name, "init_task_tag") == 0) { 443 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag); 444 retval = 0; 445 } else if (ocs_strcmp(unqualified_name, "tgt_task_tag") == 0) { 446 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag); 447 retval = 0; 448 } else if (ocs_strcmp(unqualified_name, "hw_tag") == 0) { 449 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag); 450 retval = 0; 451 } else if (ocs_strcmp(unqualified_name, "tag") == 0) { 452 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag); 453 retval = 0; 454 } else if (ocs_strcmp(unqualified_name, "transferred") == 0) { 455 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred); 456 retval = 0; 457 } else if (ocs_strcmp(unqualified_name, "auto_resp") == 0) { 458 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp); 459 retval = 0; 460 } else if (ocs_strcmp(unqualified_name, "exp_xfer_len") == 0) { 461 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len); 462 retval = 0; 463 } else if (ocs_strcmp(unqualified_name, "xfer_req") == 0) { 464 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req); 465 retval = 0; 466 } 467 } 468 469 return retval; 470 } 471 472 void 473 ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *object) 474 { 475 ocs_io_t *io = (ocs_io_t *) object; 476 477 ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name); 478 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag); 479 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag); 480 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag); 481 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag); 482 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred); 483 ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp); 484 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len); 485 ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req); 486 487 } 488 489 490 491 492