1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * XXX TODO 27 * #includes cribbed from stmf.c -- undoubtedly only a small subset of these 28 * are actually needed. 29 */ 30 #include <sys/conf.h> 31 #include <sys/file.h> 32 #include <sys/ddi.h> 33 #include <sys/sunddi.h> 34 #include <sys/scsi/scsi.h> 35 #include <sys/scsi/generic/persist.h> 36 #include <sys/byteorder.h> 37 #include <sys/nvpair.h> 38 #include <sys/door.h> 39 40 #include <sys/stmf.h> 41 #include <sys/lpif.h> 42 #include <sys/stmf_ioctl.h> 43 #include <sys/portif.h> 44 #include <sys/pppt_ic_if.h> 45 46 #include "pppt.h" 47 48 /* 49 * Macros 50 */ 51 52 /* Free a struct if it was allocated */ 53 #define FREE_IF_ALLOC(m) \ 54 do { \ 55 if ((m)) kmem_free((m), sizeof (*(m))); \ 56 _NOTE(CONSTCOND) \ 57 } while (0) 58 59 /* 60 * Macros to simplify the addition of struct fields to an nvlist. 61 * The name of the fields in the nvlist is the same as the name 62 * of the struct field. 63 * 64 * These macros require an int rc and a "done:" return retval label; 65 * they assume that the nvlist is named "nvl". 66 */ 67 #define NVLIST_ADD_FIELD(type, structure, field) \ 68 do { \ 69 rc = nvlist_add_##type(nvl, #field, structure->field); \ 70 if (rc) goto done; \ 71 _NOTE(CONSTCOND) \ 72 } while (0) 73 74 /* use this macro when the array is defined as part of the struct */ 75 #define NVLIST_ADD_ARRAY(type, structure, field) \ 76 do { \ 77 rc = nvlist_add_##type##_array(nvl, #field, \ 78 structure->field, sizeof (structure->field)); \ 79 if (rc) goto done; \ 80 _NOTE(CONSTCOND) \ 81 } while (0) 82 83 /* 84 * use this macro when the array field is a ptr or you need to explictly 85 * call out the size. 86 */ 87 #define NVLIST_ADD_ARRAY_LEN(type, structure, field, len) \ 88 do { \ 89 rc = nvlist_add_##type##_array(nvl, #field, \ 90 structure->field, len); \ 91 if (rc) goto done; \ 92 _NOTE(CONSTCOND) \ 93 } while (0) 94 95 #define NVLIST_ADD_DEVID(structure, field) \ 96 do { \ 97 rc = stmf_ic_scsi_devid_desc_marshal(nvl, #field, \ 98 structure->field); \ 99 if (rc) goto done; \ 100 _NOTE(CONSTCOND) \ 101 } while (0) 102 103 #define NVLIST_ADD_RPORT(structure, field) \ 104 do { \ 105 rc = stmf_ic_remote_port_marshal(nvl, #field, \ 106 structure->field); \ 107 if (rc) goto done; \ 108 _NOTE(CONSTCOND) \ 109 } while (0) 110 111 #define NVLIST_ADD_FIELD_UINT8(structure, field) \ 112 NVLIST_ADD_FIELD(structure, field, uint8) 113 114 /* 115 * Macros to simplify the extraction of struct fields from an nvlist. 116 * The name of the fields in the nvlist is the same as the name 117 * of the struct field. 118 * 119 * Requires an int rc and a "done:" return retval label. 120 * Assumes that the nvlist is named "nvl". 121 * 122 * Sample usage: NVLIST_LOOKUP_FIELD(uint8, structname, fieldname); 123 */ 124 #define NVLIST_LOOKUP_FIELD(type, structure, field) \ 125 do { \ 126 rc = nvlist_lookup_##type(nvl, #field, \ 127 &(structure->field)); \ 128 if (rc) { \ 129 stmf_ic_nvlookup_warn(__func__, #field); \ 130 goto done; \ 131 } \ 132 _NOTE(CONSTCOND) \ 133 } while (0) 134 135 /* 136 * Look up a field which gets stored into a structure bit field. 137 * The type passed is a uint type which can hold the largest value 138 * in the bit field. 139 * 140 * Requires an int rc and a "done:" return retval label. 141 * Assumes that the nvlist is named "nvl". 142 * 143 * Sample usage: NVLIST_LOOKUP_BIT_FIELD(uint8, structname, fieldname); 144 */ 145 #define NVLIST_LOOKUP_BIT_FIELD(type, structure, field) \ 146 do { \ 147 type##_t tmp; \ 148 rc = nvlist_lookup_##type(nvl, #field, &tmp); \ 149 if (rc) { \ 150 stmf_ic_nvlookup_warn(__func__, #field); \ 151 goto done; \ 152 } \ 153 structure->field = tmp; \ 154 _NOTE(CONSTCOND) \ 155 } while (0) 156 157 /* 158 * Look up a boolean field which gets stored into a structure bit field. 159 * 160 * Requires an int rc and a "done:" return retval label. 161 * Assumes that the nvlist is named "nvl". 162 */ 163 #define NVLIST_LOOKUP_BIT_FIELD_BOOLEAN(structure, field) \ 164 do { \ 165 boolean_t tmp; \ 166 rc = nvlist_lookup_boolean_value(nvl, #field, &tmp); \ 167 if (rc) { \ 168 stmf_ic_nvlookup_warn(__func__, #field); \ 169 goto done; \ 170 } \ 171 structure->field = (tmp ? 1 : 0); \ 172 _NOTE(CONSTCOND) \ 173 } while (0) 174 175 /* shorthand for nvlist_lookup_pairs() args */ 176 #define NV_PAIR(type, strct, field) #field, DATA_TYPE_##type, &(strct->field) 177 178 /* number of times to retry the upcall to transmit */ 179 #define STMF_MSG_TRANSMIT_RETRY 3 180 181 /* 182 * How was the message constructed? 183 * 184 * We need to know this when we free the message in order to 185 * determine what to do with pointers in the message: 186 * 187 * - messages which were unmarshaled from an nvlist may point to 188 * memory within that nvlist; this memory should not be freed since 189 * it will be deallocated when we free the nvlist. 190 * 191 * - messages which built using a constructor (alloc) function may 192 * point to memory which was explicitly allocated by the constructor; 193 * it should be freed when the message is freed. 194 * 195 */ 196 typedef enum { 197 STMF_CONSTRUCTOR = 0, 198 STMF_UNMARSHAL 199 } stmf_ic_msg_construction_method_t; 200 201 202 /* 203 * Function prototypes. 204 */ 205 206 /* 207 * Helpers for msg_alloc routines, used when the msg payload is 208 * the same for multiple types of messages. 209 */ 210 static stmf_ic_msg_t *stmf_ic_reg_dereg_lun_msg_alloc( 211 stmf_ic_msg_type_t msg_type, uint8_t *lun_id, 212 char *lu_provider_name, uint16_t cb_arg_len, 213 uint8_t *cb_arg, stmf_ic_msgid_t msgid); 214 215 static stmf_ic_msg_t *stmf_ic_session_create_destroy_msg_alloc( 216 stmf_ic_msg_type_t msg_type, 217 stmf_scsi_session_t *session, 218 stmf_ic_msgid_t msgid); 219 220 static stmf_ic_msg_t *stmf_ic_echo_request_reply_msg_alloc( 221 stmf_ic_msg_type_t msg_type, 222 uint32_t data_len, 223 uint8_t *data, 224 stmf_ic_msgid_t msgid); 225 226 /* 227 * Msg free routines. 228 */ 229 static void stmf_ic_reg_port_msg_free(stmf_ic_reg_port_msg_t *m, 230 stmf_ic_msg_construction_method_t cmethod); 231 static void stmf_ic_dereg_port_msg_free(stmf_ic_dereg_port_msg_t *m, 232 stmf_ic_msg_construction_method_t cmethod); 233 static void stmf_ic_reg_dereg_lun_msg_free(stmf_ic_reg_dereg_lun_msg_t *m, 234 stmf_ic_msg_construction_method_t cmethod); 235 static void stmf_ic_scsi_cmd_msg_free(stmf_ic_scsi_cmd_msg_t *m, 236 stmf_ic_msg_construction_method_t cmethod); 237 static void stmf_ic_scsi_data_msg_free(stmf_ic_scsi_data_msg_t *m, 238 stmf_ic_msg_construction_method_t cmethod); 239 static void stmf_ic_scsi_data_xfer_done_msg_free( 240 stmf_ic_scsi_data_xfer_done_msg_t *m, 241 stmf_ic_msg_construction_method_t cmethod); 242 static void stmf_ic_scsi_status_msg_free(stmf_ic_scsi_status_msg_t *m, 243 stmf_ic_msg_construction_method_t cmethod); 244 static void stmf_ic_r2t_msg_free(stmf_ic_r2t_msg_t *m, 245 stmf_ic_msg_construction_method_t cmethod); 246 static void stmf_ic_status_msg_free(stmf_ic_status_msg_t *m, 247 stmf_ic_msg_construction_method_t cmethod); 248 static void stmf_ic_session_create_destroy_msg_free( 249 stmf_ic_session_create_destroy_msg_t *m, 250 stmf_ic_msg_construction_method_t cmethod); 251 static void stmf_ic_echo_request_reply_msg_free( 252 stmf_ic_echo_request_reply_msg_t *m, 253 stmf_ic_msg_construction_method_t cmethod); 254 255 /* 256 * Marshaling routines. 257 */ 258 static nvlist_t *stmf_ic_msg_marshal(stmf_ic_msg_t *msg); 259 static int stmf_ic_reg_port_msg_marshal(nvlist_t *nvl, void *msg); 260 static int stmf_ic_dereg_port_msg_marshal(nvlist_t *nvl, void *msg); 261 static int stmf_ic_reg_dereg_lun_msg_marshal(nvlist_t *nvl, void *msg); 262 static int stmf_ic_scsi_cmd_msg_marshal(nvlist_t *nvl, void *msg); 263 static int stmf_ic_scsi_data_msg_marshal(nvlist_t *nvl, void *msg); 264 static int stmf_ic_scsi_data_xfer_done_msg_marshal(nvlist_t *nvl, void *msg); 265 static int stmf_ic_scsi_status_msg_marshal(nvlist_t *nvl, void *msg); 266 static int stmf_ic_r2t_msg_marshal(nvlist_t *nvl, void *msg); 267 static int stmf_ic_status_msg_marshal(nvlist_t *nvl, void *msg); 268 static int stmf_ic_session_create_destroy_msg_marshal(nvlist_t *nvl, void *msg); 269 static int stmf_ic_echo_request_reply_msg_marshal(nvlist_t *nvl, void *msg); 270 static int stmf_ic_scsi_devid_desc_marshal(nvlist_t *parent_nvl, 271 char *sdid_name, scsi_devid_desc_t *sdid); 272 static int stmf_ic_remote_port_marshal(nvlist_t *parent_nvl, 273 char *rport_name, stmf_remote_port_t *rport); 274 275 /* 276 * Unmarshaling routines. 277 */ 278 static stmf_ic_msg_t *stmf_ic_msg_unmarshal(nvlist_t *nvl); 279 static void *stmf_ic_reg_port_msg_unmarshal(nvlist_t *nvl); 280 static void *stmf_ic_dereg_port_msg_unmarshal(nvlist_t *nvl); 281 static void *stmf_ic_reg_dereg_lun_msg_unmarshal(nvlist_t *nvl); 282 static void *stmf_ic_scsi_cmd_msg_unmarshal(nvlist_t *nvl); 283 static void *stmf_ic_scsi_data_msg_unmarshal(nvlist_t *nvl); 284 static void *stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvlist_t *nvl); 285 static void *stmf_ic_scsi_status_msg_unmarshal(nvlist_t *nvl); 286 static void *stmf_ic_r2t_msg_unmarshal(nvlist_t *nvl); 287 static void *stmf_ic_status_msg_unmarshal(nvlist_t *nvl); 288 static void *stmf_ic_session_create_destroy_msg_unmarshal(nvlist_t *nvl); 289 static void *stmf_ic_echo_request_reply_msg_unmarshal(nvlist_t *nvl); 290 static scsi_devid_desc_t *stmf_ic_lookup_scsi_devid_desc_and_unmarshal( 291 nvlist_t *nvl, char *field_name); 292 static scsi_devid_desc_t *stmf_ic_scsi_devid_desc_unmarshal( 293 nvlist_t *nvl_devid); 294 static uint8_t *stmf_ic_uint8_array_unmarshal(nvlist_t *nvl, char *field_name, 295 uint64_t len, uint8_t *buf); 296 static char *stmf_ic_string_unmarshal(nvlist_t *nvl, char *field_name); 297 static stmf_remote_port_t *stmf_ic_lookup_remote_port_and_unmarshal( 298 nvlist_t *nvl, char *field_name); 299 static stmf_remote_port_t *stmf_ic_remote_port_unmarshal(nvlist_t *nvl); 300 301 /* 302 * Transmit and recieve routines. 303 */ 304 stmf_ic_msg_status_t stmf_ic_transmit(char *buf, size_t size); 305 306 /* 307 * Utilities. 308 */ 309 static stmf_ic_msg_t *stmf_ic_alloc_msg_header(stmf_ic_msg_type_t msg_type, 310 stmf_ic_msgid_t msgid); 311 static size_t sizeof_scsi_devid_desc(int ident_length); 312 static char *stmf_ic_strdup(char *str); 313 static scsi_devid_desc_t *scsi_devid_desc_dup(scsi_devid_desc_t *did); 314 static stmf_remote_port_t *remote_port_dup(stmf_remote_port_t *rport); 315 static void scsi_devid_desc_free(scsi_devid_desc_t *did); 316 static inline void stmf_ic_nvlookup_warn(const char *func, char *field); 317 318 /* 319 * Send a message out over the interconnect, in the process marshalling 320 * the arguments. 321 * 322 * After being sent, the message is freed. 323 */ 324 stmf_ic_msg_status_t 325 stmf_ic_tx_msg(stmf_ic_msg_t *msg) 326 { 327 size_t size = 0; 328 nvlist_t *nvl = NULL; 329 char *buf = NULL; 330 int err = 0; 331 stmf_ic_msg_status_t status = STMF_IC_MSG_SUCCESS; 332 333 nvl = stmf_ic_msg_marshal(msg); 334 if (!nvl) { 335 cmn_err(CE_WARN, "stmf_ic_tx_msg: marshal failed"); 336 status = STMF_IC_MSG_INTERNAL_ERROR; 337 goto done; 338 } 339 340 err = nvlist_size(nvl, &size, NV_ENCODE_XDR); 341 if (err) { 342 status = STMF_IC_MSG_INTERNAL_ERROR; 343 goto done; 344 } 345 346 buf = kmem_alloc(size, KM_SLEEP); 347 err = nvlist_pack(nvl, &buf, &size, NV_ENCODE_XDR, 0); 348 if (err) { 349 status = STMF_IC_MSG_INTERNAL_ERROR; 350 goto done; 351 } 352 353 /* push the bits out on the wire */ 354 355 status = stmf_ic_transmit(buf, size); 356 357 done: 358 if (nvl) 359 nvlist_free(nvl); 360 361 if (buf) 362 kmem_free(buf, size); 363 364 stmf_ic_msg_free(msg); 365 366 367 return (status); 368 } 369 370 /* 371 * Pass the command to the daemon for transmission to the other node. 372 */ 373 stmf_ic_msg_status_t 374 stmf_ic_transmit(char *buf, size_t size) 375 { 376 int i; 377 int rc; 378 door_arg_t arg; 379 door_handle_t door; 380 uint32_t result; 381 382 mutex_enter(&pppt_global.global_door_lock); 383 if (pppt_global.global_door == NULL) { 384 /* daemon not listening */ 385 mutex_exit(&pppt_global.global_door_lock); 386 return (STMF_IC_MSG_INTERNAL_ERROR); 387 } 388 door = pppt_global.global_door; 389 door_ki_hold(door); 390 mutex_exit(&pppt_global.global_door_lock); 391 392 arg.data_ptr = buf; 393 arg.data_size = size; 394 arg.desc_ptr = NULL; 395 arg.desc_num = 0; 396 arg.rbuf = (char *)&result; 397 arg.rsize = sizeof (result); 398 /* 399 * Retry a few times if there is a shortage of threads to 400 * service the upcall. This shouldn't happen unless a large 401 * number of initiators issue commands at once. 402 */ 403 for (i = 0; i < STMF_MSG_TRANSMIT_RETRY; i++) { 404 rc = door_ki_upcall(door, &arg); 405 if (rc != EAGAIN) 406 break; 407 delay(hz); 408 } 409 door_ki_rele(door); 410 if (rc != 0) { 411 cmn_err(CE_WARN, 412 "stmf_ic_transmit door_ki_upcall failed %d", rc); 413 return (STMF_IC_MSG_INTERNAL_ERROR); 414 } 415 if (result != 0) { 416 /* XXX Just warn for now */ 417 cmn_err(CE_WARN, 418 "stmf_ic_transmit bad result from daemon %d", result); 419 } 420 421 return (STMF_IC_MSG_SUCCESS); 422 } 423 424 /* 425 * This is a low-level upcall which is called when a message has 426 * been received on the interconnect. 427 * 428 * The caller is responsible for freeing the buffer which is passed in. 429 */ 430 /*ARGSUSED*/ 431 void 432 stmf_ic_rx_msg(char *buf, size_t len) 433 { 434 nvlist_t *nvl = NULL; 435 stmf_ic_msg_t *m = NULL; 436 stmf_ic_echo_request_reply_msg_t *icerr; 437 stmf_ic_msg_t *echo_msg; 438 int rc = 0; 439 440 rc = nvlist_unpack(buf, len, &nvl, 0); 441 if (rc) { 442 cmn_err(CE_WARN, "stmf_ic_rx_msg: unpack failed"); 443 return; 444 } 445 446 m = stmf_ic_msg_unmarshal(nvl); 447 if (m == NULL) { 448 cmn_err(CE_WARN, "stmf_ic_rx_msg: unmarshal failed"); 449 nvlist_free(nvl); 450 return; 451 } 452 453 switch (m->icm_msg_type) { 454 455 case STMF_ICM_REGISTER_PROXY_PORT: 456 case STMF_ICM_DEREGISTER_PROXY_PORT: 457 case STMF_ICM_SCSI_CMD: 458 case STMF_ICM_SCSI_DATA_XFER_DONE: 459 case STMF_ICM_SESSION_CREATE: 460 case STMF_ICM_SESSION_DESTROY: 461 /* 462 * These messages are all received by pppt. 463 * Currently, pppt will parse the message for type 464 */ 465 (void) pppt_msg_rx(m); 466 break; 467 468 case STMF_ICM_LUN_ACTIVE: 469 case STMF_ICM_REGISTER_LUN: 470 case STMF_ICM_DEREGISTER_LUN: 471 case STMF_ICM_SCSI_DATA: 472 case STMF_ICM_SCSI_STATUS: 473 /* 474 * These messages are all received by stmf. 475 * Currently, stmf will parse the message for type 476 */ 477 (void) stmf_msg_rx(m); 478 break; 479 480 case STMF_ICM_ECHO_REQUEST: 481 icerr = m->icm_msg; 482 echo_msg = stmf_ic_echo_reply_msg_alloc(icerr->icerr_datalen, 483 icerr->icerr_data, 0); 484 if (echo_msg != NULL) { 485 (void) stmf_ic_tx_msg(echo_msg); 486 } 487 stmf_ic_msg_free(m); 488 break; 489 490 case STMF_ICM_ECHO_REPLY: 491 stmf_ic_msg_free(m); 492 break; 493 494 case STMF_ICM_R2T: 495 /* 496 * XXX currently not supported 497 */ 498 stmf_ic_msg_free(m); 499 break; 500 501 case STMF_ICM_STATUS: 502 (void) stmf_msg_rx(m); 503 break; 504 505 default: 506 ASSERT(0); 507 } 508 } 509 510 /* 511 * IC message allocation routines. 512 */ 513 514 stmf_ic_msg_t * 515 stmf_ic_reg_port_msg_alloc( 516 scsi_devid_desc_t *port_id, 517 uint16_t relative_port_id, 518 uint16_t cb_arg_len, 519 uint8_t *cb_arg, 520 stmf_ic_msgid_t msgid) 521 { 522 stmf_ic_msg_t *icm = NULL; 523 stmf_ic_reg_port_msg_t *icrp = NULL; 524 525 icm = stmf_ic_alloc_msg_header(STMF_ICM_REGISTER_PROXY_PORT, msgid); 526 icrp = (stmf_ic_reg_port_msg_t *)kmem_zalloc(sizeof (*icrp), KM_SLEEP); 527 icm->icm_msg = (void *)icrp; 528 529 icrp->icrp_port_id = scsi_devid_desc_dup(port_id); 530 icrp->icrp_relative_port_id = relative_port_id; 531 532 if (cb_arg_len) { 533 icrp->icrp_cb_arg_len = cb_arg_len; 534 icrp->icrp_cb_arg = cb_arg; 535 } 536 537 return (icm); 538 } 539 540 stmf_ic_msg_t * 541 stmf_ic_dereg_port_msg_alloc( 542 scsi_devid_desc_t *port_id, 543 uint16_t cb_arg_len, 544 uint8_t *cb_arg, 545 stmf_ic_msgid_t msgid) 546 { 547 stmf_ic_msg_t *icm = NULL; 548 stmf_ic_dereg_port_msg_t *icdp = NULL; 549 550 icm = stmf_ic_alloc_msg_header(STMF_ICM_DEREGISTER_PROXY_PORT, msgid); 551 icdp = (stmf_ic_dereg_port_msg_t *)kmem_zalloc(sizeof (*icdp), 552 KM_SLEEP); 553 icm->icm_msg = (void *)icdp; 554 555 icdp->icdp_port_id = scsi_devid_desc_dup(port_id); 556 557 if (cb_arg_len) { 558 icdp->icdp_cb_arg_len = cb_arg_len; 559 icdp->icdp_cb_arg = cb_arg; 560 } 561 562 return (icm); 563 } 564 565 566 stmf_ic_msg_t * 567 stmf_ic_reg_lun_msg_alloc( 568 uint8_t *lun_id, 569 char *lu_provider_name, 570 uint16_t cb_arg_len, 571 uint8_t *cb_arg, 572 stmf_ic_msgid_t msgid) 573 { 574 return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_REGISTER_LUN, lun_id, 575 lu_provider_name, cb_arg_len, cb_arg, msgid)); 576 } 577 578 stmf_ic_msg_t * 579 stmf_ic_lun_active_msg_alloc( 580 uint8_t *lun_id, 581 char *lu_provider_name, 582 uint16_t cb_arg_len, 583 uint8_t *cb_arg, 584 stmf_ic_msgid_t msgid) 585 { 586 return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_LUN_ACTIVE, lun_id, 587 lu_provider_name, cb_arg_len, cb_arg, msgid)); 588 } 589 590 stmf_ic_msg_t * 591 stmf_ic_dereg_lun_msg_alloc( 592 uint8_t *lun_id, 593 char *lu_provider_name, 594 uint16_t cb_arg_len, 595 uint8_t *cb_arg, 596 stmf_ic_msgid_t msgid) 597 { 598 return (stmf_ic_reg_dereg_lun_msg_alloc(STMF_ICM_DEREGISTER_LUN, lun_id, 599 lu_provider_name, cb_arg_len, cb_arg, msgid)); 600 } 601 602 /* 603 * Guts of lun register/deregister/active alloc routines. 604 */ 605 static stmf_ic_msg_t * 606 stmf_ic_reg_dereg_lun_msg_alloc( 607 stmf_ic_msg_type_t msg_type, 608 uint8_t *lun_id, 609 char *lu_provider_name, 610 uint16_t cb_arg_len, 611 uint8_t *cb_arg, 612 stmf_ic_msgid_t msgid) 613 { 614 stmf_ic_msg_t *icm = NULL; 615 stmf_ic_reg_dereg_lun_msg_t *icrl = NULL; 616 617 icm = stmf_ic_alloc_msg_header(msg_type, msgid); 618 icrl = (stmf_ic_reg_dereg_lun_msg_t *) 619 kmem_zalloc(sizeof (*icrl), KM_SLEEP); 620 icm->icm_msg = (void *)icrl; 621 622 icrl->icrl_lu_provider_name = stmf_ic_strdup(lu_provider_name); 623 624 bcopy(lun_id, icrl->icrl_lun_id, sizeof (icrl->icrl_lun_id)); 625 626 if (cb_arg_len) { 627 icrl->icrl_cb_arg_len = cb_arg_len; 628 icrl->icrl_cb_arg = cb_arg; 629 } 630 631 return (icm); 632 } 633 634 stmf_ic_msg_t * 635 stmf_ic_scsi_cmd_msg_alloc( 636 stmf_ic_msgid_t task_msgid, 637 scsi_task_t *task, 638 uint32_t immed_data_len, 639 uint8_t *immed_data, 640 stmf_ic_msgid_t msgid) 641 { 642 stmf_ic_msg_t *icm = NULL; 643 stmf_ic_scsi_cmd_msg_t *icsc = NULL; 644 scsi_devid_desc_t *ini_devid = task->task_session->ss_rport_id; 645 scsi_devid_desc_t *tgt_devid = task->task_lport->lport_id; 646 stmf_remote_port_t *rport = task->task_session->ss_rport; 647 648 icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_CMD, msgid); 649 icsc = (stmf_ic_scsi_cmd_msg_t *)kmem_zalloc(sizeof (*icsc), KM_SLEEP); 650 icm->icm_msg = (void *)icsc; 651 652 icsc->icsc_task_msgid = task_msgid; 653 icsc->icsc_ini_devid = scsi_devid_desc_dup(ini_devid); 654 icsc->icsc_tgt_devid = scsi_devid_desc_dup(tgt_devid); 655 icsc->icsc_rport = remote_port_dup(rport); 656 icsc->icsc_session_id = task->task_session->ss_session_id; 657 658 if (!task->task_mgmt_function && task->task_lu->lu_id) { 659 bcopy(task->task_lu->lu_id->ident, 660 icsc->icsc_lun_id, sizeof (icsc->icsc_lun_id)); 661 } 662 663 bcopy(task->task_lun_no, icsc->icsc_task_lun_no, 664 sizeof (icsc->icsc_task_lun_no)); 665 666 icsc->icsc_task_expected_xfer_length = task->task_expected_xfer_length; 667 icsc->icsc_task_cdb_length = task->task_cdb_length; 668 669 icsc->icsc_task_cdb = (uint8_t *)kmem_zalloc(task->task_cdb_length, 670 KM_SLEEP); 671 bcopy(task->task_cdb, icsc->icsc_task_cdb, task->task_cdb_length); 672 673 icsc->icsc_task_flags = task->task_flags; 674 icsc->icsc_task_priority = task->task_priority; 675 icsc->icsc_task_mgmt_function = task->task_mgmt_function; 676 677 icsc->icsc_immed_data_len = immed_data_len; 678 icsc->icsc_immed_data = immed_data; 679 680 return (icm); 681 } 682 683 stmf_ic_msg_t * 684 stmf_ic_scsi_data_msg_alloc( 685 stmf_ic_msgid_t task_msgid, 686 uint64_t session_id, 687 uint8_t *lun_id, 688 uint64_t data_len, 689 uint8_t *data, 690 stmf_ic_msgid_t msgid) 691 { 692 stmf_ic_msg_t *icm = NULL; 693 stmf_ic_scsi_data_msg_t *icsd = NULL; 694 695 icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA, msgid); 696 icsd = (stmf_ic_scsi_data_msg_t *)kmem_zalloc(sizeof (*icsd), KM_SLEEP); 697 icm->icm_msg = (void *)icsd; 698 699 icsd->icsd_task_msgid = task_msgid; 700 icsd->icsd_session_id = session_id; 701 bcopy(lun_id, icsd->icsd_lun_id, sizeof (icsd->icsd_lun_id)); 702 icsd->icsd_data_len = data_len; 703 icsd->icsd_data = data; 704 705 return (icm); 706 } 707 708 stmf_ic_msg_t * 709 stmf_ic_scsi_data_xfer_done_msg_alloc( 710 stmf_ic_msgid_t task_msgid, 711 uint64_t session_id, 712 stmf_status_t status, 713 stmf_ic_msgid_t msgid) 714 { 715 stmf_ic_msg_t *icm = NULL; 716 stmf_ic_scsi_data_xfer_done_msg_t *icsx = NULL; 717 718 icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_DATA_XFER_DONE, msgid); 719 icsx = (stmf_ic_scsi_data_xfer_done_msg_t *)kmem_zalloc( 720 sizeof (*icsx), KM_SLEEP); 721 icm->icm_msg = (void *)icsx; 722 723 icsx->icsx_task_msgid = task_msgid; 724 icsx->icsx_session_id = session_id; 725 icsx->icsx_status = status; 726 727 return (icm); 728 } 729 730 stmf_ic_msg_t * 731 stmf_ic_scsi_status_msg_alloc( 732 stmf_ic_msgid_t task_msgid, 733 uint64_t session_id, 734 uint8_t *lun_id, 735 uint8_t response, 736 uint8_t status, 737 uint8_t flags, 738 uint32_t resid, 739 uint8_t sense_len, 740 uint8_t *sense, 741 stmf_ic_msgid_t msgid) 742 { 743 stmf_ic_msg_t *icm = NULL; 744 stmf_ic_scsi_status_msg_t *icss = NULL; 745 746 icm = stmf_ic_alloc_msg_header(STMF_ICM_SCSI_STATUS, msgid); 747 icss = (stmf_ic_scsi_status_msg_t *)kmem_zalloc(sizeof (*icss), 748 KM_SLEEP); 749 icm->icm_msg = (void *)icss; 750 751 icss->icss_task_msgid = task_msgid; 752 icss->icss_session_id = session_id; 753 bcopy(lun_id, icss->icss_lun_id, sizeof (icss->icss_lun_id)); 754 icss->icss_response = response; 755 icss->icss_status = status; 756 icss->icss_flags = flags; 757 icss->icss_resid = resid; 758 icss->icss_sense_len = sense_len; 759 icss->icss_sense = sense; 760 761 return (icm); 762 } 763 764 stmf_ic_msg_t * 765 stmf_ic_r2t_msg_alloc( 766 stmf_ic_msgid_t task_msgid, 767 uint64_t session_id, 768 uint32_t offset, 769 uint32_t length, 770 stmf_ic_msgid_t msgid) 771 { 772 stmf_ic_msg_t *icm = NULL; 773 stmf_ic_r2t_msg_t *icrt = NULL; 774 775 icm = stmf_ic_alloc_msg_header(STMF_ICM_R2T, msgid); 776 icrt = (stmf_ic_r2t_msg_t *)kmem_zalloc(sizeof (*icrt), KM_SLEEP); 777 icm->icm_msg = (void *)icrt; 778 779 icrt->icrt_task_msgid = task_msgid; 780 icrt->icrt_session_id = session_id; 781 icrt->icrt_offset = offset; 782 icrt->icrt_length = length; 783 784 return (icm); 785 } 786 787 stmf_ic_msg_t * 788 stmf_ic_status_msg_alloc( 789 stmf_status_t status, 790 stmf_ic_msg_type_t msg_type, 791 stmf_ic_msgid_t msgid) 792 { 793 stmf_ic_msg_t *icm = NULL; 794 stmf_ic_status_msg_t *ics = NULL; 795 796 icm = stmf_ic_alloc_msg_header(STMF_ICM_STATUS, msgid); 797 ics = (stmf_ic_status_msg_t *)kmem_zalloc(sizeof (*ics), KM_SLEEP); 798 icm->icm_msg = (void *)ics; 799 800 ics->ics_status = status; 801 ics->ics_msg_type = msg_type; 802 ics->ics_msgid = msgid; /* XXX same as msgid in header */ 803 804 return (icm); 805 } 806 807 stmf_ic_msg_t * 808 stmf_ic_session_create_msg_alloc( 809 stmf_scsi_session_t *session, 810 stmf_ic_msgid_t msgid) 811 { 812 return (stmf_ic_session_create_destroy_msg_alloc( 813 STMF_ICM_SESSION_CREATE, session, msgid)); 814 } 815 816 stmf_ic_msg_t * 817 stmf_ic_session_destroy_msg_alloc( 818 stmf_scsi_session_t *session, 819 stmf_ic_msgid_t msgid) 820 { 821 return (stmf_ic_session_create_destroy_msg_alloc( 822 STMF_ICM_SESSION_DESTROY, session, msgid)); 823 } 824 825 /* 826 * Guts of session create/destroy routines. 827 */ 828 static stmf_ic_msg_t * 829 stmf_ic_session_create_destroy_msg_alloc( 830 stmf_ic_msg_type_t msg_type, 831 stmf_scsi_session_t *session, 832 stmf_ic_msgid_t msgid) 833 { 834 stmf_ic_msg_t *icm = NULL; 835 stmf_ic_session_create_destroy_msg_t *icscd = NULL; 836 scsi_devid_desc_t *ini_devid = session->ss_rport_id; 837 scsi_devid_desc_t *tgt_devid = session->ss_lport->lport_id; 838 839 icm = stmf_ic_alloc_msg_header(msg_type, msgid); 840 icscd = (stmf_ic_session_create_destroy_msg_t *) 841 kmem_zalloc(sizeof (*icscd), KM_SLEEP); 842 icm->icm_msg = (void *)icscd; 843 844 icscd->icscd_session_id = session->ss_session_id; 845 icscd->icscd_ini_devid = scsi_devid_desc_dup(ini_devid); 846 icscd->icscd_tgt_devid = scsi_devid_desc_dup(tgt_devid); 847 icscd->icscd_rport = remote_port_dup(session->ss_rport); 848 849 return (icm); 850 } 851 852 stmf_ic_msg_t * 853 stmf_ic_echo_request_msg_alloc( 854 uint32_t data_len, 855 uint8_t *data, 856 stmf_ic_msgid_t msgid) 857 { 858 return (stmf_ic_echo_request_reply_msg_alloc( 859 STMF_ICM_ECHO_REQUEST, data_len, data, msgid)); 860 } 861 862 stmf_ic_msg_t * 863 stmf_ic_echo_reply_msg_alloc( 864 uint32_t data_len, 865 uint8_t *data, 866 stmf_ic_msgid_t msgid) 867 { 868 return (stmf_ic_echo_request_reply_msg_alloc( 869 STMF_ICM_ECHO_REPLY, data_len, data, msgid)); 870 } 871 872 873 static stmf_ic_msg_t * 874 stmf_ic_echo_request_reply_msg_alloc( 875 stmf_ic_msg_type_t msg_type, 876 uint32_t data_len, 877 uint8_t *data, 878 stmf_ic_msgid_t msgid) 879 { 880 stmf_ic_msg_t *icm = NULL; 881 stmf_ic_echo_request_reply_msg_t *icerr = NULL; 882 883 icm = stmf_ic_alloc_msg_header(msg_type, msgid); 884 icerr = kmem_zalloc(sizeof (*icerr), KM_SLEEP); 885 icm->icm_msg = (void *)icerr; 886 887 icerr->icerr_data = data; 888 icerr->icerr_datalen = data_len; 889 890 return (icm); 891 } 892 893 /* 894 * msg free routines. 895 */ 896 void 897 stmf_ic_msg_free(stmf_ic_msg_t *msg) 898 { 899 stmf_ic_msg_construction_method_t cmethod = 900 (msg->icm_nvlist ? STMF_UNMARSHAL : STMF_CONSTRUCTOR); 901 902 switch (msg->icm_msg_type) { 903 case STMF_ICM_REGISTER_PROXY_PORT: 904 stmf_ic_reg_port_msg_free( 905 (stmf_ic_reg_port_msg_t *)msg->icm_msg, cmethod); 906 break; 907 908 case STMF_ICM_DEREGISTER_PROXY_PORT: 909 stmf_ic_dereg_port_msg_free( 910 (stmf_ic_dereg_port_msg_t *)msg->icm_msg, cmethod); 911 break; 912 913 case STMF_ICM_LUN_ACTIVE: 914 case STMF_ICM_REGISTER_LUN: 915 case STMF_ICM_DEREGISTER_LUN: 916 stmf_ic_reg_dereg_lun_msg_free( 917 (stmf_ic_reg_dereg_lun_msg_t *)msg->icm_msg, cmethod); 918 break; 919 920 case STMF_ICM_SCSI_CMD: 921 stmf_ic_scsi_cmd_msg_free( 922 (stmf_ic_scsi_cmd_msg_t *)msg->icm_msg, cmethod); 923 break; 924 925 case STMF_ICM_SCSI_DATA: 926 stmf_ic_scsi_data_msg_free( 927 (stmf_ic_scsi_data_msg_t *)msg->icm_msg, cmethod); 928 break; 929 930 case STMF_ICM_SCSI_DATA_XFER_DONE: 931 stmf_ic_scsi_data_xfer_done_msg_free( 932 (stmf_ic_scsi_data_xfer_done_msg_t *)msg->icm_msg, cmethod); 933 break; 934 935 case STMF_ICM_SCSI_STATUS: 936 stmf_ic_scsi_status_msg_free( 937 (stmf_ic_scsi_status_msg_t *)msg->icm_msg, cmethod); 938 break; 939 940 case STMF_ICM_R2T: 941 stmf_ic_r2t_msg_free( 942 (stmf_ic_r2t_msg_t *)msg->icm_msg, cmethod); 943 break; 944 945 case STMF_ICM_STATUS: 946 stmf_ic_status_msg_free( 947 (stmf_ic_status_msg_t *)msg->icm_msg, cmethod); 948 break; 949 950 case STMF_ICM_SESSION_CREATE: 951 case STMF_ICM_SESSION_DESTROY: 952 stmf_ic_session_create_destroy_msg_free( 953 (stmf_ic_session_create_destroy_msg_t *)msg->icm_msg, 954 cmethod); 955 break; 956 957 case STMF_ICM_ECHO_REQUEST: 958 case STMF_ICM_ECHO_REPLY: 959 stmf_ic_echo_request_reply_msg_free( 960 (stmf_ic_echo_request_reply_msg_t *)msg->icm_msg, cmethod); 961 break; 962 963 case STMF_ICM_MAX_MSG_TYPE: 964 ASSERT(0); 965 break; 966 967 default: 968 ASSERT(0); 969 } 970 971 if (msg->icm_nvlist) 972 nvlist_free(msg->icm_nvlist); 973 974 kmem_free(msg, sizeof (*msg)); 975 } 976 977 /*ARGSUSED*/ 978 static void 979 stmf_ic_reg_port_msg_free(stmf_ic_reg_port_msg_t *m, 980 stmf_ic_msg_construction_method_t cmethod) 981 { 982 scsi_devid_desc_free(m->icrp_port_id); 983 984 kmem_free(m, sizeof (*m)); 985 } 986 987 988 /*ARGSUSED*/ 989 static void 990 stmf_ic_dereg_port_msg_free(stmf_ic_dereg_port_msg_t *m, 991 stmf_ic_msg_construction_method_t cmethod) 992 { 993 scsi_devid_desc_free(m->icdp_port_id); 994 995 kmem_free(m, sizeof (*m)); 996 } 997 998 999 /* 1000 * Works for both reg_lun_msg and dereg_lun_msg, since the message 1001 * payload is the same. 1002 */ 1003 static void 1004 stmf_ic_reg_dereg_lun_msg_free(stmf_ic_reg_dereg_lun_msg_t *m, 1005 stmf_ic_msg_construction_method_t cmethod) 1006 { 1007 if (cmethod == STMF_CONSTRUCTOR) { 1008 kmem_free(m->icrl_lu_provider_name, 1009 strlen(m->icrl_lu_provider_name) + 1); 1010 } 1011 1012 kmem_free(m, sizeof (*m)); 1013 } 1014 1015 static void 1016 stmf_ic_scsi_cmd_msg_free(stmf_ic_scsi_cmd_msg_t *m, 1017 stmf_ic_msg_construction_method_t cmethod) 1018 { 1019 scsi_devid_desc_free(m->icsc_ini_devid); 1020 scsi_devid_desc_free(m->icsc_tgt_devid); 1021 stmf_remote_port_free(m->icsc_rport); 1022 if (cmethod == STMF_CONSTRUCTOR) { 1023 kmem_free(m->icsc_task_cdb, m->icsc_task_cdb_length); 1024 } 1025 1026 kmem_free(m, sizeof (*m)); 1027 1028 } 1029 1030 /*ARGSUSED*/ 1031 static void 1032 stmf_ic_scsi_data_msg_free(stmf_ic_scsi_data_msg_t *m, 1033 stmf_ic_msg_construction_method_t cmethod) 1034 { 1035 kmem_free(m, sizeof (*m)); 1036 } 1037 1038 /*ARGSUSED*/ 1039 static void 1040 stmf_ic_scsi_data_xfer_done_msg_free(stmf_ic_scsi_data_xfer_done_msg_t *m, 1041 stmf_ic_msg_construction_method_t cmethod) 1042 { 1043 kmem_free(m, sizeof (*m)); 1044 } 1045 1046 /*ARGSUSED*/ 1047 static void 1048 stmf_ic_scsi_status_msg_free(stmf_ic_scsi_status_msg_t *m, 1049 stmf_ic_msg_construction_method_t cmethod) 1050 { 1051 kmem_free(m, sizeof (*m)); 1052 } 1053 1054 /*ARGSUSED*/ 1055 static void 1056 stmf_ic_r2t_msg_free(stmf_ic_r2t_msg_t *m, 1057 stmf_ic_msg_construction_method_t cmethod) 1058 { 1059 kmem_free(m, sizeof (*m)); 1060 } 1061 1062 /*ARGSUSED*/ 1063 static void 1064 stmf_ic_status_msg_free(stmf_ic_status_msg_t *m, 1065 stmf_ic_msg_construction_method_t cmethod) 1066 { 1067 kmem_free(m, sizeof (*m)); 1068 } 1069 1070 /* 1071 * Works for both session_create and session_destroy msgs, since the message 1072 * payload is the same. 1073 */ 1074 /*ARGSUSED*/ 1075 static void 1076 stmf_ic_session_create_destroy_msg_free(stmf_ic_session_create_destroy_msg_t *m, 1077 stmf_ic_msg_construction_method_t cmethod) 1078 { 1079 scsi_devid_desc_free(m->icscd_ini_devid); 1080 scsi_devid_desc_free(m->icscd_tgt_devid); 1081 stmf_remote_port_free(m->icscd_rport); 1082 1083 kmem_free(m, sizeof (*m)); 1084 } 1085 1086 /*ARGSUSED*/ 1087 static void 1088 stmf_ic_echo_request_reply_msg_free(stmf_ic_echo_request_reply_msg_t *m, 1089 stmf_ic_msg_construction_method_t cmethod) 1090 { 1091 kmem_free(m, sizeof (*m)); 1092 } 1093 1094 1095 /* 1096 * Marshaling routines. 1097 */ 1098 1099 static nvlist_t * 1100 stmf_ic_msg_marshal(stmf_ic_msg_t *msg) 1101 { 1102 nvlist_t *nvl = NULL; 1103 int rc = 0; 1104 1105 rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 1106 if (rc) 1107 goto done; 1108 1109 NVLIST_ADD_FIELD(uint8, msg, icm_msg_type); 1110 NVLIST_ADD_FIELD(uint64, msg, icm_msgid); 1111 1112 switch (msg->icm_msg_type) { 1113 case STMF_ICM_REGISTER_PROXY_PORT: 1114 rc = stmf_ic_reg_port_msg_marshal(nvl, msg->icm_msg); 1115 break; 1116 1117 1118 case STMF_ICM_DEREGISTER_PROXY_PORT: 1119 rc = stmf_ic_dereg_port_msg_marshal(nvl, msg->icm_msg); 1120 break; 1121 1122 case STMF_ICM_LUN_ACTIVE: 1123 case STMF_ICM_REGISTER_LUN: 1124 case STMF_ICM_DEREGISTER_LUN: 1125 rc = stmf_ic_reg_dereg_lun_msg_marshal(nvl, msg->icm_msg); 1126 break; 1127 1128 case STMF_ICM_SCSI_CMD: 1129 rc = stmf_ic_scsi_cmd_msg_marshal(nvl, msg->icm_msg); 1130 break; 1131 1132 case STMF_ICM_SCSI_DATA: 1133 rc = stmf_ic_scsi_data_msg_marshal(nvl, msg->icm_msg); 1134 break; 1135 1136 case STMF_ICM_SCSI_DATA_XFER_DONE: 1137 rc = stmf_ic_scsi_data_xfer_done_msg_marshal(nvl, msg->icm_msg); 1138 break; 1139 1140 case STMF_ICM_SCSI_STATUS: 1141 rc = stmf_ic_scsi_status_msg_marshal(nvl, msg->icm_msg); 1142 break; 1143 1144 case STMF_ICM_R2T: 1145 rc = stmf_ic_r2t_msg_marshal(nvl, msg->icm_msg); 1146 break; 1147 1148 case STMF_ICM_STATUS: 1149 rc = stmf_ic_status_msg_marshal(nvl, msg->icm_msg); 1150 break; 1151 1152 case STMF_ICM_SESSION_CREATE: 1153 case STMF_ICM_SESSION_DESTROY: 1154 rc = stmf_ic_session_create_destroy_msg_marshal(nvl, 1155 msg->icm_msg); 1156 break; 1157 1158 case STMF_ICM_ECHO_REQUEST: 1159 case STMF_ICM_ECHO_REPLY: 1160 rc = stmf_ic_echo_request_reply_msg_marshal(nvl, 1161 msg->icm_msg); 1162 break; 1163 1164 case STMF_ICM_MAX_MSG_TYPE: 1165 ASSERT(0); 1166 break; 1167 1168 default: 1169 ASSERT(0); 1170 } 1171 1172 done: 1173 if (!rc) 1174 return (nvl); 1175 1176 if (nvl) 1177 nvlist_free(nvl); 1178 1179 return (NULL); 1180 } 1181 1182 1183 static int 1184 stmf_ic_reg_port_msg_marshal(nvlist_t *nvl, void *msg) 1185 { 1186 stmf_ic_reg_port_msg_t *m = (stmf_ic_reg_port_msg_t *)msg; 1187 int rc = 0; 1188 1189 NVLIST_ADD_DEVID(m, icrp_port_id); 1190 NVLIST_ADD_FIELD(uint16, m, icrp_relative_port_id); 1191 1192 NVLIST_ADD_FIELD(uint16, m, icrp_cb_arg_len); 1193 /* only add the callback arg if necessary */ 1194 if (m->icrp_cb_arg_len) { 1195 NVLIST_ADD_ARRAY_LEN(uint8, m, icrp_cb_arg, m->icrp_cb_arg_len); 1196 } 1197 1198 done: 1199 return (rc); 1200 } 1201 1202 static int 1203 stmf_ic_dereg_port_msg_marshal(nvlist_t *nvl, void *msg) 1204 { 1205 stmf_ic_dereg_port_msg_t *m = (stmf_ic_dereg_port_msg_t *)msg; 1206 int rc = 0; 1207 1208 NVLIST_ADD_DEVID(m, icdp_port_id); 1209 NVLIST_ADD_FIELD(uint16, m, icdp_cb_arg_len); 1210 1211 /* only add the callback arg if necessary */ 1212 if (m->icdp_cb_arg_len) { 1213 NVLIST_ADD_ARRAY_LEN(uint8, m, icdp_cb_arg, m->icdp_cb_arg_len); 1214 } 1215 1216 done: 1217 return (rc); 1218 } 1219 1220 /* 1221 * Handles STMF_ICM_LUN_ACTIVE, STMF_ICM_REGISTER_LUN and 1222 * STMF_ICM_DEREGISTER_LUN; 1223 * msg payload is the same for all. 1224 */ 1225 static int 1226 stmf_ic_reg_dereg_lun_msg_marshal(nvlist_t *nvl, void *msg) 1227 { 1228 stmf_ic_reg_dereg_lun_msg_t *m = (stmf_ic_reg_dereg_lun_msg_t *)msg; 1229 int rc = 0; 1230 1231 NVLIST_ADD_ARRAY(uint8, m, icrl_lun_id); 1232 NVLIST_ADD_FIELD(string, m, icrl_lu_provider_name); 1233 NVLIST_ADD_FIELD(uint16, m, icrl_cb_arg_len); 1234 1235 /* only add the callback arg if necessary */ 1236 if (m->icrl_cb_arg_len) { 1237 NVLIST_ADD_ARRAY_LEN(uint8, m, icrl_cb_arg, m->icrl_cb_arg_len); 1238 } 1239 1240 done: 1241 return (rc); 1242 } 1243 1244 static int 1245 stmf_ic_scsi_cmd_msg_marshal(nvlist_t *nvl, void *msg) 1246 { 1247 stmf_ic_scsi_cmd_msg_t *m = (stmf_ic_scsi_cmd_msg_t *)msg; 1248 int rc = 0; 1249 1250 NVLIST_ADD_FIELD(uint64, m, icsc_task_msgid); 1251 NVLIST_ADD_DEVID(m, icsc_ini_devid); 1252 NVLIST_ADD_DEVID(m, icsc_tgt_devid); 1253 NVLIST_ADD_RPORT(m, icsc_rport); 1254 NVLIST_ADD_ARRAY(uint8, m, icsc_lun_id); 1255 NVLIST_ADD_FIELD(uint64, m, icsc_session_id); 1256 NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_lun_no, 8); 1257 NVLIST_ADD_FIELD(uint32, m, icsc_task_expected_xfer_length); 1258 NVLIST_ADD_FIELD(uint16, m, icsc_task_cdb_length); 1259 NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_task_cdb, m->icsc_task_cdb_length); 1260 NVLIST_ADD_FIELD(uint8, m, icsc_task_flags); 1261 NVLIST_ADD_FIELD(uint8, m, icsc_task_priority); 1262 NVLIST_ADD_FIELD(uint8, m, icsc_task_mgmt_function); 1263 1264 NVLIST_ADD_FIELD(uint32, m, icsc_immed_data_len); 1265 /* only add immediate data if necessary */ 1266 if (m->icsc_immed_data_len) { 1267 NVLIST_ADD_ARRAY_LEN(uint8, m, icsc_immed_data, 1268 m->icsc_immed_data_len); 1269 } 1270 1271 done: 1272 return (rc); 1273 } 1274 1275 static int 1276 stmf_ic_scsi_data_msg_marshal(nvlist_t *nvl, void *msg) 1277 { 1278 stmf_ic_scsi_data_msg_t *m = (stmf_ic_scsi_data_msg_t *)msg; 1279 int rc = 0; 1280 1281 NVLIST_ADD_FIELD(uint64, m, icsd_task_msgid); 1282 NVLIST_ADD_FIELD(uint64, m, icsd_session_id); 1283 NVLIST_ADD_ARRAY(uint8, m, icsd_lun_id); 1284 NVLIST_ADD_FIELD(uint64, m, icsd_data_len); 1285 NVLIST_ADD_ARRAY_LEN(uint8, m, icsd_data, m->icsd_data_len); 1286 1287 done: 1288 return (rc); 1289 } 1290 1291 static int 1292 stmf_ic_scsi_data_xfer_done_msg_marshal(nvlist_t *nvl, void *msg) 1293 { 1294 stmf_ic_scsi_data_xfer_done_msg_t *m = 1295 (stmf_ic_scsi_data_xfer_done_msg_t *)msg; 1296 int rc = 0; 1297 1298 NVLIST_ADD_FIELD(uint64, m, icsx_task_msgid); 1299 NVLIST_ADD_FIELD(uint64, m, icsx_session_id); 1300 NVLIST_ADD_FIELD(uint64, m, icsx_status); 1301 1302 done: 1303 return (rc); 1304 } 1305 1306 static int 1307 stmf_ic_scsi_status_msg_marshal(nvlist_t *nvl, void *msg) 1308 { 1309 stmf_ic_scsi_status_msg_t *m = (stmf_ic_scsi_status_msg_t *)msg; 1310 int rc = 0; 1311 1312 NVLIST_ADD_FIELD(uint64, m, icss_task_msgid); 1313 NVLIST_ADD_FIELD(uint64, m, icss_session_id); 1314 NVLIST_ADD_ARRAY(uint8, m, icss_lun_id); 1315 NVLIST_ADD_FIELD(uint8, m, icss_response); 1316 NVLIST_ADD_FIELD(uint8, m, icss_status); 1317 NVLIST_ADD_FIELD(uint8, m, icss_flags); 1318 NVLIST_ADD_FIELD(uint32, m, icss_resid); 1319 1320 NVLIST_ADD_FIELD(uint8, m, icss_sense_len); 1321 1322 if (m->icss_sense_len) 1323 NVLIST_ADD_ARRAY_LEN(uint8, m, icss_sense, m->icss_sense_len); 1324 1325 done: 1326 return (rc); 1327 } 1328 1329 static int 1330 stmf_ic_r2t_msg_marshal(nvlist_t *nvl, void *msg) 1331 { 1332 stmf_ic_r2t_msg_t *m = (stmf_ic_r2t_msg_t *)msg; 1333 int rc = 0; 1334 1335 NVLIST_ADD_FIELD(uint64, m, icrt_task_msgid); 1336 NVLIST_ADD_FIELD(uint64, m, icrt_session_id); 1337 NVLIST_ADD_FIELD(uint32, m, icrt_offset); 1338 NVLIST_ADD_FIELD(uint32, m, icrt_length); 1339 1340 done: 1341 return (rc); 1342 } 1343 1344 static int 1345 stmf_ic_status_msg_marshal(nvlist_t *nvl, void *msg) 1346 { 1347 stmf_ic_status_msg_t *m = (stmf_ic_status_msg_t *)msg; 1348 int rc = 0; 1349 1350 NVLIST_ADD_FIELD(uint8, m, ics_msg_type); 1351 NVLIST_ADD_FIELD(uint64, m, ics_msgid); 1352 NVLIST_ADD_FIELD(uint8, m, ics_status); 1353 1354 done: 1355 return (rc); 1356 } 1357 1358 static int 1359 stmf_ic_session_create_destroy_msg_marshal(nvlist_t *nvl, void *msg) 1360 { 1361 stmf_ic_session_create_destroy_msg_t *m = 1362 (stmf_ic_session_create_destroy_msg_t *)msg; 1363 int rc = 0; 1364 1365 NVLIST_ADD_DEVID(m, icscd_ini_devid); 1366 NVLIST_ADD_DEVID(m, icscd_tgt_devid); 1367 NVLIST_ADD_RPORT(m, icscd_rport); 1368 NVLIST_ADD_FIELD(uint64, m, icscd_session_id); 1369 1370 done: 1371 return (rc); 1372 } 1373 1374 static int 1375 stmf_ic_echo_request_reply_msg_marshal(nvlist_t *nvl, void *msg) 1376 { 1377 stmf_ic_echo_request_reply_msg_t *m = msg; 1378 int rc = 0; 1379 1380 NVLIST_ADD_FIELD(uint32, m, icerr_datalen); 1381 if (m->icerr_datalen) 1382 NVLIST_ADD_ARRAY_LEN(uint8, m, icerr_data, m->icerr_datalen); 1383 1384 done: 1385 return (rc); 1386 } 1387 1388 /* 1389 * Allocate a new nvlist representing the scsi_devid_desc and add it 1390 * to the nvlist. 1391 */ 1392 static int 1393 stmf_ic_scsi_devid_desc_marshal(nvlist_t *parent_nvl, 1394 char *sdid_name, 1395 scsi_devid_desc_t *sdid) 1396 { 1397 int rc = 0; 1398 nvlist_t *nvl = NULL; 1399 1400 rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 1401 if (rc) 1402 goto done; 1403 1404 NVLIST_ADD_FIELD(uint8, sdid, protocol_id); 1405 NVLIST_ADD_FIELD(uint8, sdid, code_set); 1406 NVLIST_ADD_FIELD(uint8, sdid, piv); 1407 NVLIST_ADD_FIELD(uint8, sdid, association); 1408 NVLIST_ADD_FIELD(uint8, sdid, ident_type); 1409 NVLIST_ADD_FIELD(uint8, sdid, ident_length); 1410 1411 rc = nvlist_add_uint8_array(nvl, "ident", sdid->ident, 1412 sdid->ident_length); 1413 if (rc) 1414 goto done; 1415 1416 rc = nvlist_add_nvlist(parent_nvl, sdid_name, nvl); 1417 done: 1418 if (nvl) { 1419 nvlist_free(nvl); 1420 } 1421 return (rc); 1422 } 1423 1424 /* 1425 * Allocate a new nvlist representing the stmf_remote_port and add it 1426 * to the nvlist. 1427 */ 1428 static int 1429 stmf_ic_remote_port_marshal(nvlist_t *parent_nvl, char *rport_name, 1430 stmf_remote_port_t *rport) { 1431 1432 int rc = 0; 1433 nvlist_t *nvl = NULL; 1434 1435 rc = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP); 1436 if (rc) 1437 goto done; 1438 1439 NVLIST_ADD_FIELD(uint16, rport, rport_tptid_sz); 1440 rc = nvlist_add_uint8_array(nvl, "rport_tptid", 1441 (uint8_t *)rport->rport_tptid, rport->rport_tptid_sz); 1442 if (rc) 1443 goto done; 1444 1445 rc = nvlist_add_nvlist(parent_nvl, rport_name, nvl); 1446 done: 1447 if (nvl) { 1448 nvlist_free(nvl); 1449 } 1450 return (rc); 1451 } 1452 1453 /* 1454 * Unmarshaling routines. 1455 */ 1456 1457 static stmf_ic_msg_t * 1458 stmf_ic_msg_unmarshal(nvlist_t *nvl) 1459 { 1460 stmf_ic_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1461 uint8_t msg_type; 1462 int rc = 0; 1463 1464 /* 1465 * We'd like to do this: 1466 * 1467 * NVLIST_LOOKUP_FIELD(uint8, m, icm_msg_type); 1468 * 1469 * but the fact that msg type is an enum causes type problems. 1470 */ 1471 rc = nvlist_lookup_uint8(nvl, "icm_msg_type", &msg_type); 1472 if (rc) { 1473 stmf_ic_nvlookup_warn(__func__, "icm_msg_type"); 1474 goto done; 1475 } 1476 1477 m->icm_msg_type = msg_type; 1478 m->icm_nvlist = nvl; 1479 1480 NVLIST_LOOKUP_FIELD(uint64, m, icm_msgid); 1481 1482 switch (m->icm_msg_type) { 1483 1484 case STMF_ICM_REGISTER_PROXY_PORT: 1485 m->icm_msg = stmf_ic_reg_port_msg_unmarshal(nvl); 1486 break; 1487 1488 1489 case STMF_ICM_DEREGISTER_PROXY_PORT: 1490 m->icm_msg = stmf_ic_dereg_port_msg_unmarshal(nvl); 1491 break; 1492 1493 case STMF_ICM_LUN_ACTIVE: 1494 case STMF_ICM_REGISTER_LUN: 1495 case STMF_ICM_DEREGISTER_LUN: 1496 m->icm_msg = stmf_ic_reg_dereg_lun_msg_unmarshal(nvl); 1497 break; 1498 1499 case STMF_ICM_SCSI_CMD: 1500 m->icm_msg = stmf_ic_scsi_cmd_msg_unmarshal(nvl); 1501 break; 1502 1503 case STMF_ICM_SCSI_DATA: 1504 m->icm_msg = stmf_ic_scsi_data_msg_unmarshal(nvl); 1505 break; 1506 1507 case STMF_ICM_SCSI_DATA_XFER_DONE: 1508 m->icm_msg = stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvl); 1509 break; 1510 1511 case STMF_ICM_SCSI_STATUS: 1512 m->icm_msg = stmf_ic_scsi_status_msg_unmarshal(nvl); 1513 break; 1514 1515 case STMF_ICM_R2T: 1516 m->icm_msg = stmf_ic_r2t_msg_unmarshal(nvl); 1517 break; 1518 1519 case STMF_ICM_STATUS: 1520 m->icm_msg = stmf_ic_status_msg_unmarshal(nvl); 1521 break; 1522 1523 case STMF_ICM_SESSION_CREATE: 1524 case STMF_ICM_SESSION_DESTROY: 1525 m->icm_msg = stmf_ic_session_create_destroy_msg_unmarshal(nvl); 1526 break; 1527 1528 case STMF_ICM_ECHO_REQUEST: 1529 case STMF_ICM_ECHO_REPLY: 1530 m->icm_msg = stmf_ic_echo_request_reply_msg_unmarshal(nvl); 1531 break; 1532 1533 case STMF_ICM_MAX_MSG_TYPE: 1534 ASSERT(0); 1535 break; 1536 1537 default: 1538 ASSERT(0); 1539 } 1540 1541 done: 1542 1543 if (!m->icm_msg) { 1544 kmem_free(m, sizeof (*m)); 1545 return (NULL); 1546 } 1547 1548 return (m); 1549 } 1550 1551 static void * 1552 stmf_ic_reg_port_msg_unmarshal(nvlist_t *nvl) 1553 { 1554 nvlist_t *nvl_port_id = NULL; 1555 int rc = 0; 1556 stmf_ic_reg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1557 1558 rc = nvlist_lookup_nvlist(nvl, "icrp_port_id", &nvl_port_id); 1559 if (rc) { 1560 stmf_ic_nvlookup_warn(__func__, "icrp_port_id nvl"); 1561 rc = ENOMEM; /* XXX */ 1562 goto done; 1563 } 1564 1565 m->icrp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id); 1566 if (m->icrp_port_id == NULL) { 1567 stmf_ic_nvlookup_warn(__func__, "icrp_port_id"); 1568 rc = ENOMEM; /* XXX */ 1569 goto done; 1570 } 1571 1572 NVLIST_LOOKUP_FIELD(uint16, m, icrp_relative_port_id); 1573 NVLIST_LOOKUP_FIELD(uint16, m, icrp_cb_arg_len); 1574 1575 if (m->icrp_cb_arg_len) { 1576 m->icrp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl, 1577 "icrp_cb_arg", m->icrp_cb_arg_len, NULL); 1578 if (m->icrp_cb_arg == NULL) { 1579 stmf_ic_nvlookup_warn(__func__, "icrp_cb_arg"); 1580 rc = ENOMEM; /* XXX */ 1581 goto done; 1582 } 1583 } 1584 1585 done: 1586 if (!rc) 1587 return (m); 1588 1589 stmf_ic_reg_port_msg_free(m, STMF_UNMARSHAL); 1590 1591 return (NULL); 1592 } 1593 1594 /* 1595 * XXX largely the same as stmf_ic_reg_port_msg_unmarshal() 1596 * Common stuff should be factored out. Type issues may make this 1597 * painful. 1598 */ 1599 static void * 1600 stmf_ic_dereg_port_msg_unmarshal(nvlist_t *nvl) 1601 { 1602 nvlist_t *nvl_port_id = NULL; 1603 int rc = 0; 1604 stmf_ic_dereg_port_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1605 1606 rc = nvlist_lookup_nvlist(nvl, "icdp_port_id", &nvl_port_id); 1607 if (rc) { 1608 stmf_ic_nvlookup_warn(__func__, "icdp_port_id nvl"); 1609 goto done; 1610 } 1611 1612 m->icdp_port_id = stmf_ic_scsi_devid_desc_unmarshal(nvl_port_id); 1613 if (m->icdp_port_id == NULL) { 1614 stmf_ic_nvlookup_warn(__func__, "icdp_port_id"); 1615 rc = ENOMEM; /* XXX */ 1616 goto done; 1617 } 1618 1619 NVLIST_LOOKUP_FIELD(uint16, m, icdp_cb_arg_len); 1620 1621 if (m->icdp_cb_arg_len) { 1622 m->icdp_cb_arg = stmf_ic_uint8_array_unmarshal(nvl, 1623 "icdp_cb_arg", m->icdp_cb_arg_len, NULL); 1624 if (m->icdp_cb_arg == NULL) { 1625 stmf_ic_nvlookup_warn(__func__, "icdp_cb_arg"); 1626 rc = ENOMEM; /* XXX */ 1627 goto done; 1628 } 1629 } 1630 1631 done: 1632 if (!rc) 1633 return (m); 1634 1635 stmf_ic_dereg_port_msg_free(m, STMF_UNMARSHAL); 1636 1637 return (NULL); 1638 } 1639 1640 static void * 1641 stmf_ic_reg_dereg_lun_msg_unmarshal(nvlist_t *nvl) 1642 { 1643 int rc = 0; 1644 stmf_ic_reg_dereg_lun_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1645 1646 if (! stmf_ic_uint8_array_unmarshal(nvl, "icrl_lun_id", 1647 sizeof (m->icrl_lun_id), m->icrl_lun_id)) { 1648 stmf_ic_nvlookup_warn(__func__, "icrl_lun_id"); 1649 rc = ENOMEM; /* XXX */ 1650 goto done; 1651 } 1652 1653 m->icrl_lu_provider_name = stmf_ic_string_unmarshal(nvl, 1654 "icrl_lu_provider_name"); 1655 1656 if (!m->icrl_lu_provider_name) { 1657 stmf_ic_nvlookup_warn(__func__, "icrl_lu_provider_name"); 1658 rc = ENOMEM; /* XXX */ 1659 goto done; 1660 } 1661 1662 NVLIST_LOOKUP_FIELD(uint16, m, icrl_cb_arg_len); 1663 1664 if (m->icrl_cb_arg_len) { 1665 m->icrl_cb_arg = stmf_ic_uint8_array_unmarshal(nvl, 1666 "icrl_cb_arg", m->icrl_cb_arg_len, NULL); 1667 if (m->icrl_cb_arg == NULL) { 1668 stmf_ic_nvlookup_warn(__func__, "icrl_cb_arg"); 1669 rc = ENOMEM; /* XXX */ 1670 goto done; 1671 } 1672 } 1673 1674 done: 1675 if (!rc) 1676 return (m); 1677 1678 stmf_ic_reg_dereg_lun_msg_free(m, STMF_UNMARSHAL); 1679 1680 return (NULL); 1681 } 1682 1683 static void * 1684 stmf_ic_scsi_cmd_msg_unmarshal(nvlist_t *nvl) 1685 { 1686 int rc = 0; 1687 stmf_ic_scsi_cmd_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1688 1689 if (nvlist_lookup_pairs(nvl, 0, 1690 NV_PAIR(UINT64, m, icsc_task_msgid), 1691 NV_PAIR(UINT64, m, icsc_session_id), 1692 NV_PAIR(UINT32, m, icsc_task_expected_xfer_length), 1693 NV_PAIR(UINT16, m, icsc_task_cdb_length), 1694 NV_PAIR(UINT8, m, icsc_task_flags), 1695 NV_PAIR(UINT8, m, icsc_task_mgmt_function), 1696 NV_PAIR(UINT32, m, icsc_immed_data_len), 1697 NULL) != 0) { 1698 stmf_ic_nvlookup_warn(__func__, "icsc_task_msgid and friends"); 1699 rc = ENOMEM; /* XXX need something better */ 1700 goto done; 1701 } 1702 1703 m->icsc_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal( 1704 nvl, "icsc_ini_devid"); 1705 if (m->icsc_ini_devid == NULL) { 1706 stmf_ic_nvlookup_warn(__func__, "icsc_ini_devid"); 1707 rc = ENOMEM; 1708 goto done; 1709 } 1710 1711 m->icsc_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal( 1712 nvl, "icsc_tgt_devid"); 1713 if (m->icsc_tgt_devid == NULL) { 1714 stmf_ic_nvlookup_warn(__func__, "icsc_tgt_devid"); 1715 rc = ENOMEM; 1716 goto done; 1717 } 1718 1719 m->icsc_rport = stmf_ic_lookup_remote_port_and_unmarshal( 1720 nvl, "icsc_rport"); 1721 if (m->icsc_rport == NULL) { 1722 stmf_ic_nvlookup_warn(__func__, "icsc_rport"); 1723 rc = ENOMEM; 1724 goto done; 1725 } 1726 1727 /* icsc_lun_id */ 1728 if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_lun_id", 1729 sizeof (m->icsc_lun_id), m->icsc_lun_id)) { 1730 stmf_ic_nvlookup_warn(__func__, "icsc_lun_id"); 1731 rc = ENOMEM; 1732 goto done; 1733 } 1734 1735 /* icsc_task_lun_no */ 1736 if (!stmf_ic_uint8_array_unmarshal(nvl, "icsc_task_lun_no", 1737 sizeof (m->icsc_task_lun_no), m->icsc_task_lun_no)) { 1738 stmf_ic_nvlookup_warn(__func__, "icsc_task_lun_no"); 1739 rc = ENOMEM; 1740 goto done; 1741 } 1742 1743 /* icsc_task_cdb */ 1744 m->icsc_task_cdb = stmf_ic_uint8_array_unmarshal(nvl, "icsc_task_cdb", 1745 m->icsc_task_cdb_length, NULL); 1746 if (!m->icsc_task_cdb) { 1747 stmf_ic_nvlookup_warn(__func__, "icsc_task_cdb"); 1748 rc = ENOMEM; 1749 goto done; 1750 } 1751 1752 /* immediate data, if there is any */ 1753 if (m->icsc_immed_data_len) { 1754 m->icsc_immed_data = stmf_ic_uint8_array_unmarshal(nvl, 1755 "icsc_immed_data", m->icsc_immed_data_len, NULL); 1756 if (!m->icsc_immed_data) { 1757 stmf_ic_nvlookup_warn(__func__, "icsc_immed_data"); 1758 rc = ENOMEM; 1759 goto done; 1760 } 1761 } 1762 1763 done: 1764 if (!rc) 1765 return (m); 1766 1767 stmf_ic_scsi_cmd_msg_free(m, STMF_UNMARSHAL); 1768 1769 return (NULL); 1770 } 1771 1772 static void * 1773 stmf_ic_scsi_data_msg_unmarshal(nvlist_t *nvl) 1774 { 1775 int rc = 0; 1776 stmf_ic_scsi_data_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1777 1778 if (nvlist_lookup_pairs(nvl, 0, 1779 NV_PAIR(UINT64, m, icsd_task_msgid), 1780 NV_PAIR(UINT64, m, icsd_session_id), 1781 NV_PAIR(UINT64, m, icsd_data_len), 1782 NULL) != 0) { 1783 stmf_ic_nvlookup_warn(__func__, "icsd_task_msgid and friends"); 1784 rc = ENOMEM; /* XXX need something better */ 1785 goto done; 1786 } 1787 1788 if (!stmf_ic_uint8_array_unmarshal(nvl, "icsd_lun_id", 1789 sizeof (m->icsd_lun_id), m->icsd_lun_id)) { 1790 stmf_ic_nvlookup_warn(__func__, "icsd_lun_id"); 1791 rc = ENOMEM; 1792 goto done; 1793 } 1794 1795 m->icsd_data = stmf_ic_uint8_array_unmarshal(nvl, "icsd_data", 1796 m->icsd_data_len, NULL); 1797 if (!m->icsd_data) { 1798 stmf_ic_nvlookup_warn(__func__, "icsd_data"); 1799 rc = ENOMEM; 1800 goto done; 1801 } 1802 1803 done: 1804 if (!rc) 1805 return (m); 1806 1807 stmf_ic_scsi_data_msg_free(m, STMF_UNMARSHAL); 1808 1809 return (NULL); 1810 } 1811 1812 static void * 1813 stmf_ic_scsi_data_xfer_done_msg_unmarshal(nvlist_t *nvl) 1814 { 1815 int rc = 0; 1816 stmf_ic_scsi_data_xfer_done_msg_t *m = 1817 kmem_zalloc(sizeof (*m), KM_SLEEP); 1818 1819 if (nvlist_lookup_pairs(nvl, 0, 1820 NV_PAIR(UINT64, m, icsx_task_msgid), 1821 NV_PAIR(UINT64, m, icsx_session_id), 1822 NV_PAIR(UINT64, m, icsx_status), 1823 NULL) != 0) { 1824 stmf_ic_nvlookup_warn(__func__, "icsx_task_msgid and friends"); 1825 rc = ENOMEM; /* XXX need something better */ 1826 goto done; 1827 } 1828 1829 done: 1830 if (!rc) 1831 return (m); 1832 1833 stmf_ic_scsi_data_xfer_done_msg_free(m, STMF_UNMARSHAL); 1834 1835 return (NULL); 1836 } 1837 1838 static void * 1839 stmf_ic_scsi_status_msg_unmarshal(nvlist_t *nvl) 1840 { 1841 int rc = 0; 1842 stmf_ic_scsi_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1843 1844 if (nvlist_lookup_pairs(nvl, 0, 1845 NV_PAIR(UINT64, m, icss_task_msgid), 1846 NV_PAIR(UINT64, m, icss_session_id), 1847 NV_PAIR(UINT8, m, icss_response), 1848 NV_PAIR(UINT8, m, icss_status), 1849 NV_PAIR(UINT8, m, icss_flags), 1850 NV_PAIR(UINT32, m, icss_resid), 1851 NV_PAIR(UINT8, m, icss_sense_len), 1852 NULL) != 0) { 1853 stmf_ic_nvlookup_warn(__func__, "icss_task_msgid and friends"); 1854 rc = ENOMEM; /* XXX need something better */ 1855 goto done; 1856 } 1857 1858 if (!stmf_ic_uint8_array_unmarshal(nvl, "icss_lun_id", 1859 sizeof (m->icss_lun_id), m->icss_lun_id)) { 1860 stmf_ic_nvlookup_warn(__func__, "icss_lun_id"); 1861 rc = ENOMEM; 1862 goto done; 1863 } 1864 1865 if (m->icss_sense_len) { 1866 m->icss_sense = stmf_ic_uint8_array_unmarshal(nvl, "icss_sense", 1867 m->icss_sense_len, NULL); 1868 if (!m->icss_sense) { 1869 stmf_ic_nvlookup_warn(__func__, "icss_sense"); 1870 rc = ENOMEM; 1871 goto done; 1872 } 1873 } 1874 done: 1875 if (!rc) 1876 return (m); 1877 1878 stmf_ic_scsi_status_msg_free(m, STMF_UNMARSHAL); 1879 1880 return (NULL); 1881 } 1882 1883 static void * 1884 stmf_ic_r2t_msg_unmarshal(nvlist_t *nvl) 1885 { 1886 int rc = 0; 1887 stmf_ic_r2t_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1888 1889 if (nvlist_lookup_pairs(nvl, 0, 1890 NV_PAIR(UINT64, m, icrt_task_msgid), 1891 NV_PAIR(UINT64, m, icrt_session_id), 1892 NV_PAIR(UINT32, m, icrt_offset), 1893 NV_PAIR(UINT32, m, icrt_length), 1894 NULL) != 0) { 1895 stmf_ic_nvlookup_warn(__func__, "icrt_task_msgid and friends"); 1896 rc = ENOMEM; /* XXX need something better */ 1897 goto done; 1898 } 1899 1900 done: 1901 if (!rc) 1902 return (m); 1903 1904 stmf_ic_r2t_msg_free(m, STMF_UNMARSHAL); 1905 1906 return (NULL); 1907 } 1908 1909 static void * 1910 stmf_ic_session_create_destroy_msg_unmarshal(nvlist_t *nvl) 1911 { 1912 int rc = 0; 1913 stmf_ic_session_create_destroy_msg_t *m = kmem_zalloc(sizeof (*m), 1914 KM_SLEEP); 1915 1916 if (nvlist_lookup_pairs(nvl, 0, 1917 NV_PAIR(UINT64, m, icscd_session_id), 1918 NULL) != 0) { 1919 stmf_ic_nvlookup_warn(__func__, "icsd_session_id"); 1920 rc = ENOMEM; /* XXX need something better */ 1921 goto done; 1922 } 1923 1924 m->icscd_ini_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal( 1925 nvl, "icscd_ini_devid"); 1926 if (m->icscd_ini_devid == NULL) { 1927 stmf_ic_nvlookup_warn(__func__, "icsd_ini_devid"); 1928 rc = ENOMEM; 1929 goto done; 1930 } 1931 1932 m->icscd_tgt_devid = stmf_ic_lookup_scsi_devid_desc_and_unmarshal( 1933 nvl, "icscd_tgt_devid"); 1934 if (m->icscd_tgt_devid == NULL) { 1935 stmf_ic_nvlookup_warn(__func__, "icsd_tgt_devid"); 1936 rc = ENOMEM; 1937 goto done; 1938 } 1939 1940 m->icscd_rport = stmf_ic_lookup_remote_port_and_unmarshal( 1941 nvl, "icscd_rport"); 1942 if (m->icscd_rport == NULL) { 1943 stmf_ic_nvlookup_warn(__func__, "icscd_rport"); 1944 rc = ENOMEM; 1945 goto done; 1946 } 1947 1948 done: 1949 if (!rc) 1950 return (m); 1951 1952 stmf_ic_session_create_destroy_msg_free(m, STMF_UNMARSHAL); 1953 1954 return (NULL); 1955 } 1956 1957 static void * 1958 stmf_ic_echo_request_reply_msg_unmarshal(nvlist_t *nvl) 1959 { 1960 int rc = 0; 1961 stmf_ic_echo_request_reply_msg_t *m = kmem_zalloc(sizeof (*m), 1962 KM_SLEEP); 1963 1964 if (nvlist_lookup_pairs(nvl, 0, 1965 NV_PAIR(UINT32, m, icerr_datalen), 1966 NULL) != 0) { 1967 stmf_ic_nvlookup_warn(__func__, "icerr_datalen"); 1968 rc = ENOMEM; /* XXX need something better */ 1969 goto done; 1970 } 1971 1972 /* immediate data, if there is any */ 1973 if (m->icerr_datalen) { 1974 m->icerr_data = stmf_ic_uint8_array_unmarshal(nvl, 1975 "icerr_data", m->icerr_datalen, NULL); 1976 if (!m->icerr_data) { 1977 stmf_ic_nvlookup_warn(__func__, "icerr_data"); 1978 rc = ENOMEM; 1979 goto done; 1980 } 1981 } 1982 1983 done: 1984 if (!rc) 1985 return (m); 1986 1987 stmf_ic_echo_request_reply_msg_free(m, STMF_UNMARSHAL); 1988 1989 return (NULL); 1990 } 1991 1992 static void * 1993 stmf_ic_status_msg_unmarshal(nvlist_t *nvl) 1994 { 1995 int rc = 0; 1996 stmf_ic_status_msg_t *m = kmem_zalloc(sizeof (*m), KM_SLEEP); 1997 1998 if (nvlist_lookup_pairs(nvl, 0, 1999 NV_PAIR(UINT8, m, ics_msg_type), 2000 NV_PAIR(UINT64, m, ics_msgid), 2001 NV_PAIR(UINT8, m, ics_status), 2002 NULL) != 0) { 2003 stmf_ic_nvlookup_warn(__func__, "ics_msg_type and friends"); 2004 rc = ENOMEM; /* XXX need something better */ 2005 goto done; 2006 } 2007 2008 done: 2009 if (!rc) 2010 return (m); 2011 2012 kmem_free(m, sizeof (*m)); 2013 return (NULL); 2014 } 2015 2016 2017 static scsi_devid_desc_t * 2018 stmf_ic_lookup_scsi_devid_desc_and_unmarshal(nvlist_t *nvl, char *field_name) 2019 { 2020 nvlist_t *nvl_devid = NULL; 2021 scsi_devid_desc_t *did = NULL; 2022 int rc; 2023 2024 rc = nvlist_lookup_nvlist(nvl, field_name, &nvl_devid); 2025 if (rc) { 2026 goto done; 2027 } 2028 2029 did = stmf_ic_scsi_devid_desc_unmarshal(nvl_devid); 2030 2031 done: 2032 return (did); 2033 } 2034 2035 2036 static scsi_devid_desc_t * 2037 stmf_ic_scsi_devid_desc_unmarshal(nvlist_t *nvl) 2038 { 2039 scsi_devid_desc_t *sdid = NULL; 2040 uint8_t ident_length = 0; 2041 size_t sdid_size; 2042 int rc = 0; 2043 2044 /* 2045 * we get the ident_length first, since that's the only 2046 * variable-sized field in the struct. 2047 */ 2048 rc = nvlist_lookup_uint8(nvl, "ident_length", &ident_length); 2049 if (rc) 2050 goto done; 2051 2052 sdid_size = sizeof_scsi_devid_desc(ident_length); 2053 sdid = kmem_zalloc(sdid_size, KM_SLEEP); 2054 2055 NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, protocol_id); 2056 NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, code_set); 2057 NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, piv); 2058 NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, association); 2059 NVLIST_LOOKUP_BIT_FIELD(uint8, sdid, ident_type); 2060 2061 sdid->ident_length = ident_length; 2062 2063 if (!stmf_ic_uint8_array_unmarshal(nvl, "ident", 2064 sdid->ident_length, sdid->ident)) { 2065 rc = ENOMEM; /* XXX */ 2066 goto done; 2067 } 2068 2069 done: 2070 if (!rc) 2071 return (sdid); 2072 2073 kmem_free(sdid, sdid_size); 2074 2075 return (NULL); 2076 } 2077 2078 static stmf_remote_port_t * 2079 stmf_ic_lookup_remote_port_and_unmarshal(nvlist_t *nvl, char *field_name) 2080 { 2081 nvlist_t *nvl_rport = NULL; 2082 2083 if (nvlist_lookup_nvlist(nvl, field_name, &nvl_rport) != 0) 2084 return (NULL); 2085 2086 return (stmf_ic_remote_port_unmarshal(nvl_rport)); 2087 } 2088 2089 static stmf_remote_port_t * 2090 stmf_ic_remote_port_unmarshal(nvlist_t *nvl) 2091 { 2092 stmf_remote_port_t *rport = NULL; 2093 uint16_t rport_tptid_sz = 0; 2094 int rc = 0; 2095 2096 rc = nvlist_lookup_uint16(nvl, "rport_tptid_sz", &rport_tptid_sz); 2097 if (rc || rport_tptid_sz < sizeof (scsi_transport_id_t)) 2098 return (NULL); 2099 2100 rport = stmf_remote_port_alloc(rport_tptid_sz); 2101 if (!stmf_ic_uint8_array_unmarshal(nvl, "rport_tptid", rport_tptid_sz, 2102 (uint8_t *)rport->rport_tptid)) { 2103 stmf_remote_port_free(rport); 2104 rport = NULL; 2105 } 2106 return (rport); 2107 } 2108 2109 /* 2110 * Unmarshal a uint8_t array. 2111 * 2112 * Takes a buf argument: 2113 * 2114 * - if non-null, the array contents are copied into the buf, 2115 * and we return a pointer to the buffer. 2116 * 2117 * - if null, we return a pointer to the unmarshaled data, which 2118 * resides in the nvlist. 2119 * 2120 * Returns NULL on failure. 2121 */ 2122 static uint8_t * 2123 stmf_ic_uint8_array_unmarshal( 2124 nvlist_t *nvl, 2125 char *field_name, 2126 uint64_t len, 2127 uint8_t *buf) /* non-NULL: copy array into buf */ 2128 { 2129 uint8_t *array = NULL; 2130 uint_t actual_len; 2131 int rc = 0; 2132 2133 rc = nvlist_lookup_uint8_array(nvl, field_name, &array, &actual_len); 2134 if (rc) { 2135 return (NULL); 2136 } 2137 2138 if (len != actual_len) { 2139 cmn_err(CE_WARN, 2140 "stmf_ic_uint8_array_unmarshal: wrong len (%d != %d)", 2141 (int)len, actual_len); 2142 return (NULL); 2143 } 2144 2145 if (buf) { 2146 /* preallocated buf, copy in */ 2147 bcopy(array, buf, len); 2148 } else { 2149 /* return a pointer to the underlying array in the nvlist */ 2150 buf = array; 2151 } 2152 2153 return (buf); 2154 } 2155 2156 /* 2157 * Unmarshal a string. 2158 * 2159 * Returns NULL on failure. 2160 */ 2161 static char * 2162 stmf_ic_string_unmarshal( 2163 nvlist_t *nvl, 2164 char *field_name) 2165 { 2166 char *s = NULL; 2167 int rc = 0; 2168 2169 rc = nvlist_lookup_string(nvl, field_name, &s); 2170 if (rc) { 2171 return (NULL); 2172 } 2173 2174 return (s); 2175 } 2176 2177 /* 2178 * Utility routines. 2179 */ 2180 2181 static stmf_ic_msg_t * 2182 stmf_ic_alloc_msg_header( 2183 stmf_ic_msg_type_t msg_type, 2184 stmf_ic_msgid_t msgid) 2185 { 2186 stmf_ic_msg_t *icm; 2187 2188 icm = (stmf_ic_msg_t *)kmem_zalloc(sizeof (*icm), KM_SLEEP); 2189 icm->icm_msg_type = msg_type; 2190 icm->icm_msgid = msgid; 2191 2192 return (icm); 2193 } 2194 2195 static size_t 2196 sizeof_scsi_devid_desc(int ident_length) 2197 { 2198 int num_ident_elems; 2199 size_t size; 2200 2201 ASSERT(ident_length > 0); 2202 2203 /* 2204 * Need to account for the fact that there's 2205 * already a single element in scsi_devid_desc_t. 2206 * 2207 * XXX would really like to have a way to determine the 2208 * sizeof (struct scsi_devid_desc.ident[0]), but 2209 * it's not clear that can be done. 2210 * Thus, this code relies on the knowledge of the type of 2211 * that field. 2212 */ 2213 num_ident_elems = ident_length - 1; 2214 size = sizeof (scsi_devid_desc_t) + 2215 (num_ident_elems * sizeof (uint8_t)); 2216 2217 return (size); 2218 } 2219 2220 2221 /* 2222 * Duplicate the scsi_devid_desc_t. 2223 */ 2224 static scsi_devid_desc_t * 2225 scsi_devid_desc_dup(scsi_devid_desc_t *did) 2226 { 2227 scsi_devid_desc_t *dup; 2228 size_t dup_size; 2229 2230 ASSERT(did->ident_length > 0); 2231 2232 dup_size = sizeof_scsi_devid_desc(did->ident_length); 2233 dup = (scsi_devid_desc_t *)kmem_zalloc(dup_size, KM_SLEEP); 2234 bcopy(did, dup, dup_size); 2235 return (dup); 2236 } 2237 2238 /* 2239 * May be called with a null pointer. 2240 */ 2241 static void 2242 scsi_devid_desc_free(scsi_devid_desc_t *did) 2243 { 2244 if (!did) 2245 return; 2246 2247 kmem_free(did, sizeof_scsi_devid_desc(did->ident_length)); 2248 } 2249 2250 /* 2251 * Duplicate the stmf_remote_port_t. 2252 */ 2253 static stmf_remote_port_t * 2254 remote_port_dup(stmf_remote_port_t *rport) 2255 { 2256 stmf_remote_port_t *dup = NULL; 2257 if (rport) { 2258 dup = stmf_remote_port_alloc(rport->rport_tptid_sz); 2259 bcopy(rport->rport_tptid, dup->rport_tptid, 2260 rport->rport_tptid_sz); 2261 } 2262 return (dup); 2263 } 2264 2265 /* 2266 * Helper functions, returns NULL if no memory. 2267 */ 2268 static char * 2269 stmf_ic_strdup(char *str) 2270 { 2271 char *copy; 2272 2273 ASSERT(str); 2274 2275 copy = kmem_zalloc(strlen(str) + 1, KM_SLEEP); 2276 (void) strcpy(copy, str); 2277 return (copy); 2278 } 2279 2280 static inline void 2281 stmf_ic_nvlookup_warn(const char *func, char *field) 2282 { 2283 cmn_err(CE_WARN, "%s: nvlist lookup of %s failed", func, field); 2284 } 2285