1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2000 Matthew Jacob 5 * Copyright (c) 2010 Spectra Logic Corporation 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions, and the following disclaimer, 13 * without modification, immediately at the beginning of the file. 14 * 2. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /** 31 * \file scsi_enc_ses.c 32 * 33 * Structures and routines specific && private to SES only 34 */ 35 36 #include <sys/cdefs.h> 37 #include <sys/param.h> 38 39 #include <sys/ctype.h> 40 #include <sys/errno.h> 41 #include <sys/kernel.h> 42 #include <sys/lock.h> 43 #include <sys/malloc.h> 44 #include <sys/mutex.h> 45 #include <sys/queue.h> 46 #include <sys/sbuf.h> 47 #include <sys/sx.h> 48 #include <sys/systm.h> 49 #include <sys/types.h> 50 51 #include <cam/cam.h> 52 #include <cam/cam_ccb.h> 53 #include <cam/cam_xpt_periph.h> 54 #include <cam/cam_periph.h> 55 56 #include <cam/scsi/scsi_message.h> 57 #include <cam/scsi/scsi_enc.h> 58 #include <cam/scsi/scsi_enc_internal.h> 59 60 /* SES Native Type Device Support */ 61 62 /* SES Diagnostic Page Codes */ 63 typedef enum { 64 SesSupportedPages = 0x0, 65 SesConfigPage = 0x1, 66 SesControlPage = 0x2, 67 SesStatusPage = SesControlPage, 68 SesHelpTxt = 0x3, 69 SesStringOut = 0x4, 70 SesStringIn = SesStringOut, 71 SesThresholdOut = 0x5, 72 SesThresholdIn = SesThresholdOut, 73 SesArrayControl = 0x6, /* Obsolete in SES v2 */ 74 SesArrayStatus = SesArrayControl, 75 SesElementDescriptor = 0x7, 76 SesShortStatus = 0x8, 77 SesEnclosureBusy = 0x9, 78 SesAddlElementStatus = 0xa 79 } SesDiagPageCodes; 80 81 typedef struct ses_type { 82 const struct ses_elm_type_desc *hdr; 83 const char *text; 84 } ses_type_t; 85 86 typedef struct ses_comstat { 87 uint8_t comstatus; 88 uint8_t comstat[3]; 89 } ses_comstat_t; 90 91 typedef union ses_addl_data { 92 struct ses_elm_sas_device_phy *sasdev_phys; 93 struct ses_elm_sas_expander_phy *sasexp_phys; 94 struct ses_elm_sas_port_phy *sasport_phys; 95 struct ses_fcobj_port *fc_ports; 96 } ses_add_data_t; 97 98 typedef struct ses_addl_status { 99 struct ses_elm_addlstatus_base_hdr *hdr; 100 union { 101 union ses_fcobj_hdr *fc; 102 union ses_elm_sas_hdr *sas; 103 struct ses_elm_ata_hdr *ata; 104 } proto_hdr; 105 union ses_addl_data proto_data; /* array sizes stored in header */ 106 } ses_add_status_t; 107 108 typedef struct ses_element { 109 uint8_t eip; /* eip bit is set */ 110 uint16_t descr_len; /* length of the descriptor */ 111 const char *descr; /* descriptor for this object */ 112 struct ses_addl_status addl; /* additional status info */ 113 } ses_element_t; 114 115 typedef struct ses_control_request { 116 int elm_idx; 117 ses_comstat_t elm_stat; 118 int result; 119 TAILQ_ENTRY(ses_control_request) links; 120 } ses_control_request_t; 121 TAILQ_HEAD(ses_control_reqlist, ses_control_request); 122 typedef struct ses_control_reqlist ses_control_reqlist_t; 123 enum { 124 SES_SETSTATUS_ENC_IDX = -1 125 }; 126 127 static void 128 ses_terminate_control_requests(ses_control_reqlist_t *reqlist, int result) 129 { 130 ses_control_request_t *req; 131 132 while ((req = TAILQ_FIRST(reqlist)) != NULL) { 133 TAILQ_REMOVE(reqlist, req, links); 134 req->result = result; 135 wakeup(req); 136 } 137 } 138 139 enum ses_iter_index_values { 140 /** 141 * \brief Value of an initialized but invalid index 142 * in a ses_iterator object. 143 * 144 * This value is used for the individual_element_index of 145 * overal status elements and for all index types when 146 * an iterator is first initialized. 147 */ 148 ITERATOR_INDEX_INVALID = -1, 149 150 /** 151 * \brief Value of an index in a ses_iterator object 152 * when the iterator has traversed past the last 153 * valid element.. 154 */ 155 ITERATOR_INDEX_END = INT_MAX 156 }; 157 158 /** 159 * \brief Structure encapsulating all data necessary to traverse the 160 * elements of a SES configuration. 161 * 162 * The ses_iterator object simplifies the task of iterating through all 163 * elements detected via the SES configuration page by tracking the numerous 164 * element indexes that, instead of memoizing in the softc, we calculate 165 * on the fly during the traversal of the element objects. The various 166 * indexes are necessary due to the varying needs of matching objects in 167 * the different SES pages. Some pages (e.g. Status/Control) contain all 168 * elements, while others (e.g. Additional Element Status) only contain 169 * individual elements (no overal status elements) of particular types. 170 * 171 * To use an iterator, initialize it with ses_iter_init(), and then 172 * use ses_iter_next() to traverse the elements (including the first) in 173 * the configuration. Once an iterator is initiailized with ses_iter_init(), 174 * you may also seek to any particular element by either it's global or 175 * individual element index via the ses_iter_seek_to() function. You may 176 * also return an iterator to the position just before the first element 177 * (i.e. the same state as after an ses_iter_init()), with ses_iter_reset(). 178 */ 179 struct ses_iterator { 180 /** 181 * \brief Backlink to the overal software configuration structure. 182 * 183 * This is included for convenience so the iteration functions 184 * need only take a single, struct ses_iterator *, argument. 185 */ 186 enc_softc_t *enc; 187 188 enc_cache_t *cache; 189 190 /** 191 * \brief Index of the type of the current element within the 192 * ses_cache's ses_types array. 193 */ 194 int type_index; 195 196 /** 197 * \brief The position (0 based) of this element relative to all other 198 * elements of this type. 199 * 200 * This index resets to zero every time the iterator transitions 201 * to elements of a new type in the configuration. 202 */ 203 int type_element_index; 204 205 /** 206 * \brief The position (0 based) of this element relative to all 207 * other individual status elements in the configuration. 208 * 209 * This index ranges from 0 through the number of individual 210 * elements in the configuration. When the iterator returns 211 * an overall status element, individual_element_index is 212 * set to ITERATOR_INDEX_INVALID, to indicate that it does 213 * not apply to the current element. 214 */ 215 int individual_element_index; 216 217 /** 218 * \brief The position (0 based) of this element relative to 219 * all elements in the configration. 220 * 221 * This index is appropriate for indexing into enc->ses_elm_map. 222 */ 223 int global_element_index; 224 225 /** 226 * \brief The last valid individual element index of this 227 * iterator. 228 * 229 * When an iterator traverses an overal status element, the 230 * individual element index is reset to ITERATOR_INDEX_INVALID 231 * to prevent unintential use of the individual_element_index 232 * field. The saved_individual_element_index allows the iterator 233 * to restore it's position in the individual elements upon 234 * reaching the next individual element. 235 */ 236 int saved_individual_element_index; 237 }; 238 239 typedef enum { 240 SES_UPDATE_NONE, 241 SES_UPDATE_PAGES, 242 SES_UPDATE_GETCONFIG, 243 SES_UPDATE_GETSTATUS, 244 SES_UPDATE_GETELMDESCS, 245 SES_UPDATE_GETELMADDLSTATUS, 246 SES_PROCESS_CONTROL_REQS, 247 SES_PUBLISH_PHYSPATHS, 248 SES_PUBLISH_CACHE, 249 SES_NUM_UPDATE_STATES 250 } ses_update_action; 251 252 static enc_softc_cleanup_t ses_softc_cleanup; 253 254 #define SCSZ 0x8000 255 256 static fsm_fill_handler_t ses_fill_rcv_diag_io; 257 static fsm_fill_handler_t ses_fill_control_request; 258 static fsm_done_handler_t ses_process_pages; 259 static fsm_done_handler_t ses_process_config; 260 static fsm_done_handler_t ses_process_status; 261 static fsm_done_handler_t ses_process_elm_descs; 262 static fsm_done_handler_t ses_process_elm_addlstatus; 263 static fsm_done_handler_t ses_process_control_request; 264 static fsm_done_handler_t ses_publish_physpaths; 265 static fsm_done_handler_t ses_publish_cache; 266 267 static struct enc_fsm_state enc_fsm_states[SES_NUM_UPDATE_STATES] = 268 { 269 { "SES_UPDATE_NONE", 0, 0, 0, NULL, NULL, NULL }, 270 { 271 "SES_UPDATE_PAGES", 272 SesSupportedPages, 273 SCSZ, 274 60 * 1000, 275 ses_fill_rcv_diag_io, 276 ses_process_pages, 277 enc_error 278 }, 279 { 280 "SES_UPDATE_GETCONFIG", 281 SesConfigPage, 282 SCSZ, 283 60 * 1000, 284 ses_fill_rcv_diag_io, 285 ses_process_config, 286 enc_error 287 }, 288 { 289 "SES_UPDATE_GETSTATUS", 290 SesStatusPage, 291 SCSZ, 292 60 * 1000, 293 ses_fill_rcv_diag_io, 294 ses_process_status, 295 enc_error 296 }, 297 { 298 "SES_UPDATE_GETELMDESCS", 299 SesElementDescriptor, 300 SCSZ, 301 60 * 1000, 302 ses_fill_rcv_diag_io, 303 ses_process_elm_descs, 304 enc_error 305 }, 306 { 307 "SES_UPDATE_GETELMADDLSTATUS", 308 SesAddlElementStatus, 309 SCSZ, 310 60 * 1000, 311 ses_fill_rcv_diag_io, 312 ses_process_elm_addlstatus, 313 enc_error 314 }, 315 { 316 "SES_PROCESS_CONTROL_REQS", 317 SesControlPage, 318 SCSZ, 319 60 * 1000, 320 ses_fill_control_request, 321 ses_process_control_request, 322 enc_error 323 }, 324 { 325 "SES_PUBLISH_PHYSPATHS", 326 0, 327 0, 328 0, 329 NULL, 330 ses_publish_physpaths, 331 NULL 332 }, 333 { 334 "SES_PUBLISH_CACHE", 335 0, 336 0, 337 0, 338 NULL, 339 ses_publish_cache, 340 NULL 341 } 342 }; 343 344 typedef struct ses_cache { 345 /* Source for all the configuration data pointers */ 346 const struct ses_cfg_page *cfg_page; 347 348 /* References into the config page. */ 349 int ses_nsubencs; 350 const struct ses_enc_desc * const *subencs; 351 int ses_ntypes; 352 const ses_type_t *ses_types; 353 354 /* Source for all the status pointers */ 355 const struct ses_status_page *status_page; 356 357 /* Source for all the object descriptor pointers */ 358 const struct ses_elem_descr_page *elm_descs_page; 359 360 /* Source for all the additional object status pointers */ 361 const struct ses_addl_elem_status_page *elm_addlstatus_page; 362 363 } ses_cache_t; 364 365 typedef struct ses_softc { 366 uint32_t ses_flags; 367 #define SES_FLAG_TIMEDCOMP 0x01 368 #define SES_FLAG_ADDLSTATUS 0x02 369 #define SES_FLAG_DESC 0x04 370 371 ses_control_reqlist_t ses_requests; 372 ses_control_reqlist_t ses_pending_requests; 373 } ses_softc_t; 374 375 static int ses_search_globally = 0; 376 SYSCTL_INT(_kern_cam_enc, OID_AUTO, search_globally, CTLFLAG_RWTUN, 377 &ses_search_globally, 0, "Search for disks on other buses"); 378 379 /** 380 * \brief Reset a SES iterator to just before the first element 381 * in the configuration. 382 * 383 * \param iter The iterator object to reset. 384 * 385 * The indexes within a reset iterator are invalid and will only 386 * become valid upon completion of a ses_iter_seek_to() or a 387 * ses_iter_next(). 388 */ 389 static void 390 ses_iter_reset(struct ses_iterator *iter) 391 { 392 /* 393 * Set our indexes to just before the first valid element 394 * of the first type (ITERATOR_INDEX_INVALID == -1). This 395 * simplifies the implementation of ses_iter_next(). 396 */ 397 iter->type_index = 0; 398 iter->type_element_index = ITERATOR_INDEX_INVALID; 399 iter->global_element_index = ITERATOR_INDEX_INVALID; 400 iter->individual_element_index = ITERATOR_INDEX_INVALID; 401 iter->saved_individual_element_index = ITERATOR_INDEX_INVALID; 402 } 403 404 /** 405 * \brief Initialize the storage of a SES iterator and reset it to 406 * the position just before the first element of the 407 * configuration. 408 * 409 * \param enc The SES softc for the SES instance whose configuration 410 * will be enumerated by this iterator. 411 * \param iter The iterator object to initialize. 412 */ 413 static void 414 ses_iter_init(enc_softc_t *enc, enc_cache_t *cache, struct ses_iterator *iter) 415 { 416 iter->enc = enc; 417 iter->cache = cache; 418 ses_iter_reset(iter); 419 } 420 421 /** 422 * \brief Traverse the provided SES iterator to the next element 423 * within the configuration. 424 * 425 * \param iter The iterator to move. 426 * 427 * \return If a valid next element exists, a pointer to it's enc_element_t. 428 * Otherwise NULL. 429 */ 430 static enc_element_t * 431 ses_iter_next(struct ses_iterator *iter) 432 { 433 ses_cache_t *ses_cache; 434 const ses_type_t *element_type; 435 436 ses_cache = iter->cache->private; 437 438 /* 439 * Note: Treat nelms as signed, so we will hit this case 440 * and immediately terminate the iteration if the 441 * configuration has 0 objects. 442 */ 443 if (iter->global_element_index >= (int)iter->cache->nelms - 1) { 444 /* Elements exhausted. */ 445 iter->type_index = ITERATOR_INDEX_END; 446 iter->type_element_index = ITERATOR_INDEX_END; 447 iter->global_element_index = ITERATOR_INDEX_END; 448 iter->individual_element_index = ITERATOR_INDEX_END; 449 iter->saved_individual_element_index = ITERATOR_INDEX_END; 450 return (NULL); 451 } 452 453 KASSERT((iter->type_index < ses_cache->ses_ntypes), 454 ("Corrupted element iterator. %d not less than %d", 455 iter->type_index, ses_cache->ses_ntypes)); 456 457 element_type = &ses_cache->ses_types[iter->type_index]; 458 iter->global_element_index++; 459 iter->type_element_index++; 460 461 /* 462 * There is an object for overal type status in addition 463 * to one for each allowed element, but only if the element 464 * count is non-zero. 465 */ 466 if (iter->type_element_index > element_type->hdr->etype_maxelt) { 467 /* 468 * We've exhausted the elements of this type. 469 * This next element belongs to the next type. 470 */ 471 iter->type_index++; 472 iter->type_element_index = 0; 473 iter->individual_element_index = ITERATOR_INDEX_INVALID; 474 } 475 476 if (iter->type_element_index > 0) { 477 iter->individual_element_index = 478 ++iter->saved_individual_element_index; 479 } 480 481 return (&iter->cache->elm_map[iter->global_element_index]); 482 } 483 484 /** 485 * Element index types tracked by a SES iterator. 486 */ 487 typedef enum { 488 /** 489 * Index relative to all elements (overall and individual) 490 * in the system. 491 */ 492 SES_ELEM_INDEX_GLOBAL, 493 494 /** 495 * \brief Index relative to all individual elements in the system. 496 * 497 * This index counts only individual elements, skipping overall 498 * status elements. This is the index space of the additional 499 * element status page (page 0xa). 500 */ 501 SES_ELEM_INDEX_INDIVIDUAL 502 } ses_elem_index_type_t; 503 504 /** 505 * \brief Move the provided iterator forwards or backwards to the object 506 * having the give index. 507 * 508 * \param iter The iterator on which to perform the seek. 509 * \param element_index The index of the element to find. 510 * \param index_type The type (global or individual) of element_index. 511 * 512 * \return If the element is found, a pointer to it's enc_element_t. 513 * Otherwise NULL. 514 */ 515 static enc_element_t * 516 ses_iter_seek_to(struct ses_iterator *iter, int element_index, 517 ses_elem_index_type_t index_type) 518 { 519 enc_element_t *element; 520 int *cur_index; 521 522 if (index_type == SES_ELEM_INDEX_GLOBAL) 523 cur_index = &iter->global_element_index; 524 else 525 cur_index = &iter->individual_element_index; 526 527 if (*cur_index == element_index) { 528 /* Already there. */ 529 return (&iter->cache->elm_map[iter->global_element_index]); 530 } 531 532 ses_iter_reset(iter); 533 while ((element = ses_iter_next(iter)) != NULL 534 && *cur_index != element_index) 535 ; 536 537 if (*cur_index != element_index) 538 return (NULL); 539 540 return (element); 541 } 542 543 #if 0 544 static int ses_encode(enc_softc_t *, uint8_t *, int, int, 545 struct ses_comstat *); 546 #endif 547 static int ses_set_timed_completion(enc_softc_t *, uint8_t); 548 #if 0 549 static int ses_putstatus(enc_softc_t *, int, struct ses_comstat *); 550 #endif 551 552 static void ses_poll_status(enc_softc_t *); 553 static void ses_print_addl_data(enc_softc_t *, enc_element_t *); 554 555 /*=========================== SES cleanup routines ===========================*/ 556 557 static void 558 ses_cache_free_elm_addlstatus(enc_softc_t *enc, enc_cache_t *cache) 559 { 560 ses_cache_t *ses_cache; 561 ses_cache_t *other_ses_cache; 562 enc_element_t *cur_elm; 563 enc_element_t *last_elm; 564 565 ENC_DLOG(enc, "%s: enter\n", __func__); 566 ses_cache = cache->private; 567 if (ses_cache->elm_addlstatus_page == NULL) 568 return; 569 570 for (cur_elm = cache->elm_map, 571 last_elm = &cache->elm_map[cache->nelms]; 572 cur_elm != last_elm; cur_elm++) { 573 ses_element_t *elmpriv; 574 575 elmpriv = cur_elm->elm_private; 576 577 /* Clear references to the additional status page. */ 578 bzero(&elmpriv->addl, sizeof(elmpriv->addl)); 579 } 580 581 other_ses_cache = enc_other_cache(enc, cache)->private; 582 if (other_ses_cache->elm_addlstatus_page 583 != ses_cache->elm_addlstatus_page) 584 ENC_FREE(ses_cache->elm_addlstatus_page); 585 ses_cache->elm_addlstatus_page = NULL; 586 } 587 588 static void 589 ses_cache_free_elm_descs(enc_softc_t *enc, enc_cache_t *cache) 590 { 591 ses_cache_t *ses_cache; 592 ses_cache_t *other_ses_cache; 593 enc_element_t *cur_elm; 594 enc_element_t *last_elm; 595 596 ENC_DLOG(enc, "%s: enter\n", __func__); 597 ses_cache = cache->private; 598 if (ses_cache->elm_descs_page == NULL) 599 return; 600 601 for (cur_elm = cache->elm_map, 602 last_elm = &cache->elm_map[cache->nelms]; 603 cur_elm != last_elm; cur_elm++) { 604 ses_element_t *elmpriv; 605 606 elmpriv = cur_elm->elm_private; 607 elmpriv->descr_len = 0; 608 elmpriv->descr = NULL; 609 } 610 611 other_ses_cache = enc_other_cache(enc, cache)->private; 612 if (other_ses_cache->elm_descs_page 613 != ses_cache->elm_descs_page) 614 ENC_FREE(ses_cache->elm_descs_page); 615 ses_cache->elm_descs_page = NULL; 616 } 617 618 static void 619 ses_cache_free_status(enc_softc_t *enc, enc_cache_t *cache) 620 { 621 ses_cache_t *ses_cache; 622 ses_cache_t *other_ses_cache; 623 624 ENC_DLOG(enc, "%s: enter\n", __func__); 625 ses_cache = cache->private; 626 if (ses_cache->status_page == NULL) 627 return; 628 629 other_ses_cache = enc_other_cache(enc, cache)->private; 630 if (other_ses_cache->status_page != ses_cache->status_page) 631 ENC_FREE(ses_cache->status_page); 632 ses_cache->status_page = NULL; 633 } 634 635 static void 636 ses_cache_free_elm_map(enc_softc_t *enc, enc_cache_t *cache) 637 { 638 enc_element_t *cur_elm; 639 enc_element_t *last_elm; 640 641 ENC_DLOG(enc, "%s: enter\n", __func__); 642 if (cache->elm_map == NULL) 643 return; 644 645 ses_cache_free_elm_descs(enc, cache); 646 ses_cache_free_elm_addlstatus(enc, cache); 647 for (cur_elm = cache->elm_map, 648 last_elm = &cache->elm_map[cache->nelms]; 649 cur_elm != last_elm; cur_elm++) { 650 ENC_FREE_AND_NULL(cur_elm->elm_private); 651 } 652 ENC_FREE_AND_NULL(cache->elm_map); 653 cache->nelms = 0; 654 ENC_DLOG(enc, "%s: exit\n", __func__); 655 } 656 657 static void 658 ses_cache_free(enc_softc_t *enc, enc_cache_t *cache) 659 { 660 ses_cache_t *other_ses_cache; 661 ses_cache_t *ses_cache; 662 663 ENC_DLOG(enc, "%s: enter\n", __func__); 664 ses_cache_free_elm_addlstatus(enc, cache); 665 ses_cache_free_status(enc, cache); 666 ses_cache_free_elm_map(enc, cache); 667 668 ses_cache = cache->private; 669 ses_cache->ses_ntypes = 0; 670 671 other_ses_cache = enc_other_cache(enc, cache)->private; 672 if (other_ses_cache->subencs != ses_cache->subencs) 673 ENC_FREE(ses_cache->subencs); 674 ses_cache->subencs = NULL; 675 676 if (other_ses_cache->ses_types != ses_cache->ses_types) 677 ENC_FREE(ses_cache->ses_types); 678 ses_cache->ses_types = NULL; 679 680 if (other_ses_cache->cfg_page != ses_cache->cfg_page) 681 ENC_FREE(ses_cache->cfg_page); 682 ses_cache->cfg_page = NULL; 683 684 ENC_DLOG(enc, "%s: exit\n", __func__); 685 } 686 687 static void 688 ses_cache_clone(enc_softc_t *enc, enc_cache_t *src, enc_cache_t *dst) 689 { 690 ses_cache_t *dst_ses_cache; 691 ses_cache_t *src_ses_cache; 692 enc_element_t *src_elm; 693 enc_element_t *dst_elm; 694 enc_element_t *last_elm; 695 696 ses_cache_free(enc, dst); 697 src_ses_cache = src->private; 698 dst_ses_cache = dst->private; 699 700 /* 701 * The cloned enclosure cache and ses specific cache are 702 * mostly identical to the source. 703 */ 704 *dst = *src; 705 *dst_ses_cache = *src_ses_cache; 706 707 /* 708 * But the ses cache storage is still independent. Restore 709 * the pointer that was clobbered by the structure copy above. 710 */ 711 dst->private = dst_ses_cache; 712 713 /* 714 * The element map is independent even though it starts out 715 * pointing to the same constant page data. 716 */ 717 dst->elm_map = malloc(dst->nelms * sizeof(enc_element_t), 718 M_SCSIENC, M_WAITOK); 719 memcpy(dst->elm_map, src->elm_map, dst->nelms * sizeof(enc_element_t)); 720 for (dst_elm = dst->elm_map, src_elm = src->elm_map, 721 last_elm = &src->elm_map[src->nelms]; 722 src_elm != last_elm; src_elm++, dst_elm++) { 723 dst_elm->elm_private = malloc(sizeof(ses_element_t), 724 M_SCSIENC, M_WAITOK); 725 memcpy(dst_elm->elm_private, src_elm->elm_private, 726 sizeof(ses_element_t)); 727 } 728 } 729 730 /* Structure accessors. These are strongly typed to avoid errors. */ 731 732 int 733 ses_elm_sas_descr_type(union ses_elm_sas_hdr *obj) 734 { 735 return ((obj)->base_hdr.byte1 >> 6); 736 } 737 int 738 ses_elm_addlstatus_proto(struct ses_elm_addlstatus_base_hdr *hdr) 739 { 740 return ((hdr)->byte0 & 0xf); 741 } 742 int 743 ses_elm_addlstatus_eip(struct ses_elm_addlstatus_base_hdr *hdr) 744 { 745 return ((hdr)->byte0 >> 4 & 0x1); 746 } 747 int 748 ses_elm_addlstatus_invalid(struct ses_elm_addlstatus_base_hdr *hdr) 749 { 750 return ((hdr)->byte0 >> 7); 751 } 752 int 753 ses_elm_sas_type0_not_all_phys(union ses_elm_sas_hdr *hdr) 754 { 755 return ((hdr)->type0_noneip.byte1 & 0x1); 756 } 757 int 758 ses_elm_sas_dev_phy_sata_dev(struct ses_elm_sas_device_phy *phy) 759 { 760 return ((phy)->target_ports & 0x1); 761 } 762 int 763 ses_elm_sas_dev_phy_sata_port(struct ses_elm_sas_device_phy *phy) 764 { 765 return ((phy)->target_ports >> 7); 766 } 767 int 768 ses_elm_sas_dev_phy_dev_type(struct ses_elm_sas_device_phy *phy) 769 { 770 return (((phy)->byte0 >> 4) & 0x7); 771 } 772 773 /** 774 * \brief Verify that the cached configuration data in our softc 775 * is valid for processing the page data corresponding to 776 * the provided page header. 777 * 778 * \param ses_cache The SES cache to validate. 779 * \param gen_code The 4 byte generation code from a SES diagnostic 780 * page header. 781 * 782 * \return non-zero if true, 0 if false. 783 */ 784 static int 785 ses_config_cache_valid(ses_cache_t *ses_cache, const uint8_t *gen_code) 786 { 787 uint32_t cache_gc; 788 uint32_t cur_gc; 789 790 if (ses_cache->cfg_page == NULL) 791 return (0); 792 793 cache_gc = scsi_4btoul(ses_cache->cfg_page->hdr.gen_code); 794 cur_gc = scsi_4btoul(gen_code); 795 return (cache_gc == cur_gc); 796 } 797 798 /** 799 * Function signature for consumers of the ses_devids_iter() interface. 800 */ 801 typedef void ses_devid_callback_t(enc_softc_t *, enc_element_t *, 802 struct scsi_vpd_id_descriptor *, void *); 803 804 /** 805 * \brief Iterate over and create vpd device id records from the 806 * additional element status data for elm, passing that data 807 * to the provided callback. 808 * 809 * \param enc SES instance containing elm 810 * \param elm Element for which to extract device ID data. 811 * \param callback The callback function to invoke on each generated 812 * device id descriptor for elm. 813 * \param callback_arg Argument passed through to callback on each invocation. 814 */ 815 static void 816 ses_devids_iter(enc_softc_t *enc, enc_element_t *elm, 817 ses_devid_callback_t *callback, void *callback_arg) 818 { 819 ses_element_t *elmpriv; 820 struct ses_addl_status *addl; 821 u_int i; 822 size_t devid_record_size; 823 824 elmpriv = elm->elm_private; 825 addl = &(elmpriv->addl); 826 827 devid_record_size = SVPD_DEVICE_ID_DESC_HDR_LEN 828 + sizeof(struct scsi_vpd_id_naa_ieee_reg); 829 for (i = 0; i < addl->proto_hdr.sas->base_hdr.num_phys; i++) { 830 uint8_t devid_buf[devid_record_size]; 831 struct scsi_vpd_id_descriptor *devid; 832 uint8_t *phy_addr; 833 834 devid = (struct scsi_vpd_id_descriptor *)devid_buf; 835 phy_addr = addl->proto_data.sasdev_phys[i].phy_addr; 836 devid->proto_codeset = (SCSI_PROTO_SAS << SVPD_ID_PROTO_SHIFT) 837 | SVPD_ID_CODESET_BINARY; 838 devid->id_type = SVPD_ID_PIV 839 | SVPD_ID_ASSOC_PORT 840 | SVPD_ID_TYPE_NAA; 841 devid->reserved = 0; 842 devid->length = sizeof(struct scsi_vpd_id_naa_ieee_reg); 843 memcpy(devid->identifier, phy_addr, devid->length); 844 845 callback(enc, elm, devid, callback_arg); 846 } 847 } 848 849 /** 850 * Function signature for consumers of the ses_paths_iter() interface. 851 */ 852 typedef void ses_path_callback_t(enc_softc_t *, enc_element_t *, 853 struct cam_path *, void *); 854 855 /** 856 * Argument package passed through ses_devids_iter() by 857 * ses_paths_iter() to ses_path_iter_devid_callback(). 858 */ 859 typedef struct ses_path_iter_args { 860 ses_path_callback_t *callback; 861 void *callback_arg; 862 } ses_path_iter_args_t; 863 864 /** 865 * ses_devids_iter() callback function used by ses_paths_iter() 866 * to map device ids to peripheral driver instances. 867 * 868 * \param enc SES instance containing elm 869 * \param elm Element on which device ID matching is active. 870 * \param periph A device ID corresponding to elm. 871 * \param arg Argument passed through to callback on each invocation. 872 */ 873 static void 874 ses_path_iter_devid_callback(enc_softc_t *enc, enc_element_t *elem, 875 struct scsi_vpd_id_descriptor *devid, 876 void *arg) 877 { 878 struct ccb_dev_match cdm; 879 struct dev_match_pattern match_pattern; 880 struct dev_match_result match_result; 881 struct device_match_result *device_match; 882 struct device_match_pattern *device_pattern; 883 ses_path_iter_args_t *args; 884 struct cam_path *path; 885 886 args = (ses_path_iter_args_t *)arg; 887 match_pattern.type = DEV_MATCH_DEVICE; 888 device_pattern = &match_pattern.pattern.device_pattern; 889 device_pattern->flags = DEV_MATCH_DEVID; 890 device_pattern->data.devid_pat.id_len = 891 offsetof(struct scsi_vpd_id_descriptor, identifier) 892 + devid->length; 893 memcpy(device_pattern->data.devid_pat.id, devid, 894 device_pattern->data.devid_pat.id_len); 895 if (!ses_search_globally) { 896 device_pattern->flags |= DEV_MATCH_PATH; 897 device_pattern->path_id = xpt_path_path_id(enc->periph->path); 898 } 899 900 memset(&cdm, 0, sizeof(cdm)); 901 if (xpt_create_path(&cdm.ccb_h.path, /*periph*/NULL, 902 CAM_XPT_PATH_ID, 903 CAM_TARGET_WILDCARD, 904 CAM_LUN_WILDCARD) != CAM_REQ_CMP) 905 return; 906 907 cdm.ccb_h.func_code = XPT_DEV_MATCH; 908 cdm.num_patterns = 1; 909 cdm.patterns = &match_pattern; 910 cdm.pattern_buf_len = sizeof(match_pattern); 911 cdm.match_buf_len = sizeof(match_result); 912 cdm.matches = &match_result; 913 914 do { 915 xpt_action((union ccb *)&cdm); 916 917 if ((cdm.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP || 918 (cdm.status != CAM_DEV_MATCH_LAST && 919 cdm.status != CAM_DEV_MATCH_MORE) || 920 cdm.num_matches == 0) 921 break; 922 923 device_match = &match_result.result.device_result; 924 if (xpt_create_path(&path, /*periph*/NULL, 925 device_match->path_id, 926 device_match->target_id, 927 device_match->target_lun) == CAM_REQ_CMP) { 928 args->callback(enc, elem, path, args->callback_arg); 929 930 xpt_free_path(path); 931 } 932 } while (cdm.status == CAM_DEV_MATCH_MORE); 933 934 xpt_free_path(cdm.ccb_h.path); 935 } 936 937 /** 938 * \brief Iterate over and find the matching periph objects for the 939 * specified element. 940 * 941 * \param enc SES instance containing elm 942 * \param elm Element for which to perform periph object matching. 943 * \param callback The callback function to invoke with each matching 944 * periph object. 945 * \param callback_arg Argument passed through to callback on each invocation. 946 */ 947 static void 948 ses_paths_iter(enc_softc_t *enc, enc_element_t *elm, 949 ses_path_callback_t *callback, void *callback_arg) 950 { 951 ses_element_t *elmpriv; 952 struct ses_addl_status *addl; 953 954 elmpriv = elm->elm_private; 955 addl = &(elmpriv->addl); 956 957 if (addl->hdr == NULL) 958 return; 959 960 switch(ses_elm_addlstatus_proto(addl->hdr)) { 961 case SPSP_PROTO_SAS: 962 if (addl->proto_hdr.sas != NULL && 963 addl->proto_data.sasdev_phys != NULL) { 964 ses_path_iter_args_t args; 965 966 args.callback = callback; 967 args.callback_arg = callback_arg; 968 ses_devids_iter(enc, elm, ses_path_iter_devid_callback, 969 &args); 970 } 971 break; 972 case SPSP_PROTO_ATA: 973 if (addl->proto_hdr.ata != NULL) { 974 struct cam_path *path; 975 struct ccb_getdev cgd; 976 977 if (xpt_create_path(&path, /*periph*/NULL, 978 scsi_4btoul(addl->proto_hdr.ata->bus), 979 scsi_4btoul(addl->proto_hdr.ata->target), 0) 980 != CAM_REQ_CMP) 981 return; 982 983 memset(&cgd, 0, sizeof(cgd)); 984 xpt_setup_ccb(&cgd.ccb_h, path, CAM_PRIORITY_NORMAL); 985 cgd.ccb_h.func_code = XPT_GDEV_TYPE; 986 xpt_action((union ccb *)&cgd); 987 if (cam_ccb_success((union ccb *)&cgd)) 988 callback(enc, elm, path, callback_arg); 989 990 xpt_free_path(path); 991 } 992 break; 993 } 994 } 995 996 /** 997 * ses_paths_iter() callback function used by ses_get_elmdevname() 998 * to record periph driver instance strings corresponding to a SES 999 * element. 1000 * 1001 * \param enc SES instance containing elm 1002 * \param elm Element on which periph matching is active. 1003 * \param periph A periph instance that matches elm. 1004 * \param arg Argument passed through to callback on each invocation. 1005 */ 1006 static void 1007 ses_elmdevname_callback(enc_softc_t *enc, enc_element_t *elem, 1008 struct cam_path *path, void *arg) 1009 { 1010 struct sbuf *sb; 1011 1012 sb = (struct sbuf *)arg; 1013 cam_periph_list(path, sb); 1014 } 1015 1016 /** 1017 * Argument package passed through ses_paths_iter() to 1018 * ses_getcampath_callback. 1019 */ 1020 typedef struct ses_setphyspath_callback_args { 1021 struct sbuf *physpath; 1022 int num_set; 1023 } ses_setphyspath_callback_args_t; 1024 1025 /** 1026 * \brief ses_paths_iter() callback to set the physical path on the 1027 * CAM EDT entries corresponding to a given SES element. 1028 * 1029 * \param enc SES instance containing elm 1030 * \param elm Element on which periph matching is active. 1031 * \param periph A periph instance that matches elm. 1032 * \param arg Argument passed through to callback on each invocation. 1033 */ 1034 static void 1035 ses_setphyspath_callback(enc_softc_t *enc, enc_element_t *elm, 1036 struct cam_path *path, void *arg) 1037 { 1038 struct ccb_dev_advinfo cdai; 1039 ses_setphyspath_callback_args_t *args; 1040 char *old_physpath; 1041 1042 args = (ses_setphyspath_callback_args_t *)arg; 1043 old_physpath = malloc(MAXPATHLEN, M_SCSIENC, M_WAITOK|M_ZERO); 1044 xpt_path_lock(path); 1045 memset(&cdai, 0, sizeof(cdai)); 1046 xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 1047 cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 1048 cdai.buftype = CDAI_TYPE_PHYS_PATH; 1049 cdai.flags = CDAI_FLAG_NONE; 1050 cdai.bufsiz = MAXPATHLEN; 1051 cdai.buf = old_physpath; 1052 xpt_action((union ccb *)&cdai); 1053 if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 1054 cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 1055 1056 if (strcmp(old_physpath, sbuf_data(args->physpath)) != 0) { 1057 xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); 1058 cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 1059 cdai.buftype = CDAI_TYPE_PHYS_PATH; 1060 cdai.flags = CDAI_FLAG_STORE; 1061 cdai.bufsiz = sbuf_len(args->physpath); 1062 cdai.buf = sbuf_data(args->physpath); 1063 xpt_action((union ccb *)&cdai); 1064 if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 1065 cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 1066 if (cam_ccb_success((union ccb *)&cdai)) 1067 args->num_set++; 1068 } 1069 xpt_path_unlock(path); 1070 free(old_physpath, M_SCSIENC); 1071 } 1072 1073 /** 1074 * \brief Set a device's physical path string in CAM XPT. 1075 * 1076 * \param enc SES instance containing elm 1077 * \param elm Element to publish physical path string for 1078 * \param iter Iterator whose state corresponds to elm 1079 * 1080 * \return 0 on success, errno otherwise. 1081 */ 1082 static int 1083 ses_set_physpath(enc_softc_t *enc, enc_element_t *elm, 1084 struct ses_iterator *iter) 1085 { 1086 struct ccb_dev_advinfo cdai; 1087 ses_setphyspath_callback_args_t args; 1088 int i, ret; 1089 struct sbuf sb; 1090 struct scsi_vpd_id_descriptor *idd; 1091 uint8_t *devid; 1092 ses_element_t *elmpriv; 1093 const char *c; 1094 1095 ret = EIO; 1096 devid = NULL; 1097 1098 elmpriv = elm->elm_private; 1099 if (elmpriv->addl.hdr == NULL) 1100 goto out; 1101 1102 /* 1103 * Assemble the components of the physical path starting with 1104 * the device ID of the enclosure itself. 1105 */ 1106 memset(&cdai, 0, sizeof(cdai)); 1107 xpt_setup_ccb(&cdai.ccb_h, enc->periph->path, CAM_PRIORITY_NORMAL); 1108 cdai.ccb_h.func_code = XPT_DEV_ADVINFO; 1109 cdai.flags = CDAI_FLAG_NONE; 1110 cdai.buftype = CDAI_TYPE_SCSI_DEVID; 1111 cdai.bufsiz = CAM_SCSI_DEVID_MAXLEN; 1112 cdai.buf = devid = malloc(cdai.bufsiz, M_SCSIENC, M_WAITOK|M_ZERO); 1113 cam_periph_lock(enc->periph); 1114 xpt_action((union ccb *)&cdai); 1115 if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) 1116 cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); 1117 cam_periph_unlock(enc->periph); 1118 if (cdai.ccb_h.status != CAM_REQ_CMP) 1119 goto out; 1120 1121 idd = scsi_get_devid((struct scsi_vpd_device_id *)cdai.buf, 1122 cdai.provsiz, scsi_devid_is_naa_ieee_reg); 1123 if (idd == NULL) 1124 goto out; 1125 1126 if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL) { 1127 ret = ENOMEM; 1128 goto out; 1129 } 1130 /* Next, generate the physical path string */ 1131 sbuf_printf(&sb, "id1,enc@n%jx/type@%x/slot@%x", 1132 scsi_8btou64(idd->identifier), iter->type_index, 1133 iter->type_element_index); 1134 /* Append the element descriptor if one exists */ 1135 if (elmpriv->descr != NULL && elmpriv->descr_len > 0) { 1136 sbuf_cat(&sb, "/elmdesc@"); 1137 for (i = 0, c = elmpriv->descr; i < elmpriv->descr_len; 1138 i++, c++) { 1139 if (!isprint(*c) || isspace(*c) || *c == '/') 1140 sbuf_putc(&sb, '_'); 1141 else 1142 sbuf_putc(&sb, *c); 1143 } 1144 } 1145 sbuf_finish(&sb); 1146 1147 /* 1148 * Set this physical path on any CAM devices with a device ID 1149 * descriptor that matches one created from the SES additional 1150 * status data for this element. 1151 */ 1152 args.physpath= &sb; 1153 args.num_set = 0; 1154 ses_paths_iter(enc, elm, ses_setphyspath_callback, &args); 1155 sbuf_delete(&sb); 1156 1157 ret = args.num_set == 0 ? ENOENT : 0; 1158 1159 out: 1160 if (devid != NULL) 1161 ENC_FREE(devid); 1162 return (ret); 1163 } 1164 1165 /** 1166 * \brief Helper to set the CDB fields appropriately. 1167 * 1168 * \param cdb Buffer containing the cdb. 1169 * \param pagenum SES diagnostic page to query for. 1170 * \param dir Direction of query. 1171 */ 1172 static void 1173 ses_page_cdb(char *cdb, int bufsiz, SesDiagPageCodes pagenum, int dir) 1174 { 1175 1176 /* Ref: SPC-4 r25 Section 6.20 Table 223 */ 1177 if (dir == CAM_DIR_IN) { 1178 cdb[0] = RECEIVE_DIAGNOSTIC; 1179 cdb[1] = 1; /* Set page code valid bit */ 1180 cdb[2] = pagenum; 1181 } else { 1182 cdb[0] = SEND_DIAGNOSTIC; 1183 cdb[1] = 0x10; 1184 cdb[2] = pagenum; 1185 } 1186 cdb[3] = bufsiz >> 8; /* high bits */ 1187 cdb[4] = bufsiz & 0xff; /* low bits */ 1188 cdb[5] = 0; 1189 } 1190 1191 /** 1192 * \brief Discover whether this instance supports timed completion of a 1193 * RECEIVE DIAGNOSTIC RESULTS command requesting the Enclosure Status 1194 * page, and store the result in the softc, updating if necessary. 1195 * 1196 * \param enc SES instance to query and update. 1197 * \param tc_en Value of timed completion to set (see \return). 1198 * 1199 * \return 1 if timed completion enabled, 0 otherwise. 1200 */ 1201 static int 1202 ses_set_timed_completion(enc_softc_t *enc, uint8_t tc_en) 1203 { 1204 union ccb *ccb; 1205 struct cam_periph *periph; 1206 struct ses_mgmt_mode_page *mgmt; 1207 uint8_t *mode_buf; 1208 size_t mode_buf_len; 1209 ses_softc_t *ses; 1210 1211 periph = enc->periph; 1212 ses = enc->enc_private; 1213 ccb = cam_periph_getccb(periph, CAM_PRIORITY_NORMAL); 1214 1215 mode_buf_len = sizeof(struct ses_mgmt_mode_page); 1216 mode_buf = ENC_MALLOCZ(mode_buf_len); 1217 if (mode_buf == NULL) 1218 goto out; 1219 1220 scsi_mode_sense(&ccb->csio, /*retries*/4, NULL, MSG_SIMPLE_Q_TAG, 1221 /*dbd*/FALSE, SMS_PAGE_CTRL_CURRENT, SES_MGMT_MODE_PAGE_CODE, 1222 mode_buf, mode_buf_len, SSD_FULL_SIZE, /*timeout*/60 * 1000); 1223 1224 /* 1225 * Ignore illegal request errors, as they are quite common and we 1226 * will print something out in that case anyway. 1227 */ 1228 cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, 1229 ENC_FLAGS|SF_QUIET_IR, NULL); 1230 if (ccb->ccb_h.status != CAM_REQ_CMP) { 1231 ENC_VLOG(enc, "Timed Completion Unsupported\n"); 1232 goto release; 1233 } 1234 1235 /* Skip the mode select if the desired value is already set */ 1236 mgmt = (struct ses_mgmt_mode_page *)mode_buf; 1237 if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) == tc_en) 1238 goto done; 1239 1240 /* Value is not what we wanted, set it */ 1241 if (tc_en) 1242 mgmt->byte5 |= SES_MGMT_TIMED_COMP_EN; 1243 else 1244 mgmt->byte5 &= ~SES_MGMT_TIMED_COMP_EN; 1245 /* SES2r20: a completion time of zero means as long as possible */ 1246 bzero(&mgmt->max_comp_time, sizeof(mgmt->max_comp_time)); 1247 1248 scsi_mode_select(&ccb->csio, 5, NULL, MSG_SIMPLE_Q_TAG, 1249 /*page_fmt*/FALSE, /*save_pages*/TRUE, mode_buf, mode_buf_len, 1250 SSD_FULL_SIZE, /*timeout*/60 * 1000); 1251 1252 cam_periph_runccb(ccb, enc_error, ENC_CFLAGS, ENC_FLAGS, NULL); 1253 if (ccb->ccb_h.status != CAM_REQ_CMP) { 1254 ENC_VLOG(enc, "Timed Completion Set Failed\n"); 1255 goto release; 1256 } 1257 1258 done: 1259 if ((mgmt->byte5 & SES_MGMT_TIMED_COMP_EN) != 0) { 1260 ENC_LOG(enc, "Timed Completion Enabled\n"); 1261 ses->ses_flags |= SES_FLAG_TIMEDCOMP; 1262 } else { 1263 ENC_LOG(enc, "Timed Completion Disabled\n"); 1264 ses->ses_flags &= ~SES_FLAG_TIMEDCOMP; 1265 } 1266 release: 1267 ENC_FREE(mode_buf); 1268 xpt_release_ccb(ccb); 1269 out: 1270 return (ses->ses_flags & SES_FLAG_TIMEDCOMP); 1271 } 1272 1273 /** 1274 * \brief Process the list of supported pages and update flags. 1275 * 1276 * \param enc SES device to query. 1277 * \param buf Buffer containing the config page. 1278 * \param xfer_len Length of the config page in the buffer. 1279 * 1280 * \return 0 on success, errno otherwise. 1281 */ 1282 static int 1283 ses_process_pages(enc_softc_t *enc, struct enc_fsm_state *state, 1284 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1285 { 1286 ses_softc_t *ses; 1287 struct scsi_diag_page *page; 1288 int err, i, length; 1289 1290 CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE, 1291 ("entering %s(%p, %d)\n", __func__, bufp, xfer_len)); 1292 ses = enc->enc_private; 1293 err = -1; 1294 1295 if (error != 0) { 1296 err = error; 1297 goto out; 1298 } 1299 if (xfer_len < sizeof(*page)) { 1300 ENC_VLOG(enc, "Unable to parse Diag Pages List Header\n"); 1301 err = EIO; 1302 goto out; 1303 } 1304 page = (struct scsi_diag_page *)*bufp; 1305 length = scsi_2btoul(page->length); 1306 if (length + offsetof(struct scsi_diag_page, params) > xfer_len) { 1307 ENC_VLOG(enc, "Diag Pages List Too Long\n"); 1308 goto out; 1309 } 1310 ENC_DLOG(enc, "%s: page length %d, xfer_len %d\n", 1311 __func__, length, xfer_len); 1312 1313 err = 0; 1314 for (i = 0; i < length; i++) { 1315 if (page->params[i] == SesElementDescriptor) 1316 ses->ses_flags |= SES_FLAG_DESC; 1317 else if (page->params[i] == SesAddlElementStatus) 1318 ses->ses_flags |= SES_FLAG_ADDLSTATUS; 1319 } 1320 1321 out: 1322 ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err); 1323 return (err); 1324 } 1325 1326 /** 1327 * \brief Process the config page and update associated structures. 1328 * 1329 * \param enc SES device to query. 1330 * \param buf Buffer containing the config page. 1331 * \param xfer_len Length of the config page in the buffer. 1332 * 1333 * \return 0 on success, errno otherwise. 1334 */ 1335 static int 1336 ses_process_config(enc_softc_t *enc, struct enc_fsm_state *state, 1337 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1338 { 1339 struct ses_iterator iter; 1340 enc_cache_t *enc_cache; 1341 ses_cache_t *ses_cache; 1342 uint8_t *buf; 1343 int length; 1344 int err; 1345 int nelm; 1346 int ntype; 1347 struct ses_cfg_page *cfg_page; 1348 struct ses_enc_desc *buf_subenc; 1349 const struct ses_enc_desc **subencs; 1350 const struct ses_enc_desc **cur_subenc; 1351 const struct ses_enc_desc **last_subenc; 1352 ses_type_t *ses_types; 1353 ses_type_t *sestype; 1354 const struct ses_elm_type_desc *cur_buf_type; 1355 const struct ses_elm_type_desc *last_buf_type; 1356 uint8_t *last_valid_byte; 1357 enc_element_t *element; 1358 const char *type_text; 1359 1360 CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE, 1361 ("entering %s(%p, %d)\n", __func__, bufp, xfer_len)); 1362 enc_cache = &enc->enc_daemon_cache; 1363 ses_cache = enc_cache->private; 1364 buf = *bufp; 1365 err = -1; 1366 1367 if (error != 0) { 1368 err = error; 1369 goto out; 1370 } 1371 if (xfer_len < sizeof(cfg_page->hdr)) { 1372 ENC_VLOG(enc, "Unable to parse SES Config Header\n"); 1373 err = EIO; 1374 goto out; 1375 } 1376 1377 cfg_page = (struct ses_cfg_page *)buf; 1378 length = ses_page_length(&cfg_page->hdr); 1379 if (length > xfer_len) { 1380 ENC_VLOG(enc, "Enclosure Config Page Too Long\n"); 1381 goto out; 1382 } 1383 last_valid_byte = &buf[length - 1]; 1384 1385 ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n", 1386 __func__, length, xfer_len); 1387 1388 err = 0; 1389 if (ses_config_cache_valid(ses_cache, cfg_page->hdr.gen_code)) { 1390 /* Our cache is still valid. Proceed to fetching status. */ 1391 goto out; 1392 } 1393 1394 /* Cache is no longer valid. Free old data to make way for new. */ 1395 ses_cache_free(enc, enc_cache); 1396 ENC_VLOG(enc, "Generation Code 0x%x has %d SubEnclosures\n", 1397 scsi_4btoul(cfg_page->hdr.gen_code), 1398 ses_cfg_page_get_num_subenc(cfg_page)); 1399 1400 /* Take ownership of the buffer. */ 1401 ses_cache->cfg_page = cfg_page; 1402 *bufp = NULL; 1403 1404 /* 1405 * Now waltz through all the subenclosures summing the number of 1406 * types available in each. 1407 */ 1408 subencs = malloc(ses_cfg_page_get_num_subenc(cfg_page) 1409 * sizeof(*subencs), M_SCSIENC, M_WAITOK|M_ZERO); 1410 /* 1411 * Sub-enclosure data is const after construction (i.e. when 1412 * accessed via our cache object. 1413 * 1414 * The cast here is not required in C++ but C99 is not so 1415 * sophisticated (see C99 6.5.16.1(1)). 1416 */ 1417 ses_cache->ses_nsubencs = ses_cfg_page_get_num_subenc(cfg_page); 1418 ses_cache->subencs = subencs; 1419 1420 buf_subenc = cfg_page->subencs; 1421 cur_subenc = subencs; 1422 last_subenc = &subencs[ses_cache->ses_nsubencs - 1]; 1423 ntype = 0; 1424 while (cur_subenc <= last_subenc) { 1425 if (!ses_enc_desc_is_complete(buf_subenc, last_valid_byte)) { 1426 ENC_VLOG(enc, "Enclosure %d Beyond End of " 1427 "Descriptors\n", cur_subenc - subencs); 1428 err = EIO; 1429 goto out; 1430 } 1431 1432 ENC_VLOG(enc, " SubEnclosure ID %d, %d Types With this ID, " 1433 "Descriptor Length %d, offset %d\n", buf_subenc->subenc_id, 1434 buf_subenc->num_types, buf_subenc->length, 1435 &buf_subenc->byte0 - buf); 1436 ENC_VLOG(enc, "WWN: %jx\n", 1437 (uintmax_t)scsi_8btou64(buf_subenc->logical_id)); 1438 1439 ntype += buf_subenc->num_types; 1440 *cur_subenc = buf_subenc; 1441 cur_subenc++; 1442 buf_subenc = ses_enc_desc_next(buf_subenc); 1443 } 1444 1445 /* Process the type headers. */ 1446 ses_types = malloc(ntype * sizeof(*ses_types), 1447 M_SCSIENC, M_WAITOK|M_ZERO); 1448 /* 1449 * Type data is const after construction (i.e. when accessed via 1450 * our cache object. 1451 */ 1452 ses_cache->ses_ntypes = ntype; 1453 ses_cache->ses_types = ses_types; 1454 1455 cur_buf_type = (const struct ses_elm_type_desc *) 1456 (&(*last_subenc)->length + (*last_subenc)->length + 1); 1457 last_buf_type = cur_buf_type + ntype - 1; 1458 type_text = (const uint8_t *)(last_buf_type + 1); 1459 nelm = 0; 1460 sestype = ses_types; 1461 while (cur_buf_type <= last_buf_type) { 1462 if (&cur_buf_type->etype_txt_len > last_valid_byte) { 1463 ENC_VLOG(enc, "Runt Enclosure Type Header %d\n", 1464 sestype - ses_types); 1465 err = EIO; 1466 goto out; 1467 } 1468 sestype->hdr = cur_buf_type; 1469 sestype->text = type_text; 1470 type_text += cur_buf_type->etype_txt_len; 1471 ENC_VLOG(enc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc " 1472 "%d, Text Length %d: %.*s\n", sestype - ses_types, 1473 sestype->hdr->etype_elm_type, sestype->hdr->etype_maxelt, 1474 sestype->hdr->etype_subenc, sestype->hdr->etype_txt_len, 1475 sestype->hdr->etype_txt_len, sestype->text); 1476 1477 nelm += sestype->hdr->etype_maxelt 1478 + /*overall status element*/1; 1479 sestype++; 1480 cur_buf_type++; 1481 } 1482 1483 /* Create the object map. */ 1484 enc_cache->elm_map = malloc(nelm * sizeof(enc_element_t), 1485 M_SCSIENC, M_WAITOK|M_ZERO); 1486 enc_cache->nelms = nelm; 1487 1488 ses_iter_init(enc, enc_cache, &iter); 1489 while ((element = ses_iter_next(&iter)) != NULL) { 1490 const struct ses_elm_type_desc *thdr; 1491 1492 ENC_DLOG(enc, "%s: checking obj %d(%d,%d)\n", __func__, 1493 iter.global_element_index, iter.type_index, nelm, 1494 iter.type_element_index); 1495 thdr = ses_cache->ses_types[iter.type_index].hdr; 1496 element->elm_idx = iter.global_element_index; 1497 element->elm_type = thdr->etype_elm_type; 1498 element->subenclosure = thdr->etype_subenc; 1499 element->type_elm_idx = iter.type_element_index; 1500 element->elm_private = malloc(sizeof(ses_element_t), 1501 M_SCSIENC, M_WAITOK|M_ZERO); 1502 ENC_DLOG(enc, "%s: creating elmpriv %d(%d,%d) subenc %d " 1503 "type 0x%x\n", __func__, iter.global_element_index, 1504 iter.type_index, iter.type_element_index, 1505 thdr->etype_subenc, thdr->etype_elm_type); 1506 } 1507 1508 err = 0; 1509 1510 out: 1511 if (err) 1512 ses_cache_free(enc, enc_cache); 1513 else { 1514 ses_poll_status(enc); 1515 enc_update_request(enc, SES_PUBLISH_CACHE); 1516 } 1517 ENC_DLOG(enc, "%s: exiting with err %d\n", __func__, err); 1518 return (err); 1519 } 1520 1521 /** 1522 * \brief Update the status page and associated structures. 1523 * 1524 * \param enc SES softc to update for. 1525 * \param buf Buffer containing the status page. 1526 * \param bufsz Amount of data in the buffer. 1527 * 1528 * \return 0 on success, errno otherwise. 1529 */ 1530 static int 1531 ses_process_status(enc_softc_t *enc, struct enc_fsm_state *state, 1532 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1533 { 1534 struct ses_iterator iter; 1535 enc_element_t *element; 1536 ses_softc_t *ses; 1537 enc_cache_t *enc_cache; 1538 ses_cache_t *ses_cache; 1539 uint8_t *buf; 1540 int err = -1; 1541 int length; 1542 struct ses_status_page *page; 1543 union ses_status_element *cur_stat; 1544 union ses_status_element *last_stat; 1545 1546 ses = enc->enc_private; 1547 enc_cache = &enc->enc_daemon_cache; 1548 ses_cache = enc_cache->private; 1549 buf = *bufp; 1550 1551 ENC_DLOG(enc, "%s: enter (%p, %p, %d)\n", __func__, enc, buf, xfer_len); 1552 page = (struct ses_status_page *)buf; 1553 length = ses_page_length(&page->hdr); 1554 1555 if (error != 0) { 1556 err = error; 1557 goto out; 1558 } 1559 /* 1560 * Make sure the length fits in the buffer. 1561 * 1562 * XXX all this means is that the page is larger than the space 1563 * we allocated. Since we use a statically sized buffer, this 1564 * could happen... Need to use dynamic discovery of the size. 1565 */ 1566 if (length > xfer_len) { 1567 ENC_VLOG(enc, "Enclosure Status Page Too Long\n"); 1568 goto out; 1569 } 1570 1571 /* Check for simple enclosure reporting short enclosure status. */ 1572 if (length >= 4 && page->hdr.page_code == SesShortStatus) { 1573 ENC_DLOG(enc, "Got Short Enclosure Status page\n"); 1574 ses->ses_flags &= ~(SES_FLAG_ADDLSTATUS | SES_FLAG_DESC); 1575 ses_cache_free(enc, enc_cache); 1576 enc_cache->enc_status = page->hdr.page_specific_flags; 1577 enc_update_request(enc, SES_PUBLISH_CACHE); 1578 err = 0; 1579 goto out; 1580 } 1581 1582 /* Make sure the length contains at least one header and status */ 1583 if (length < (sizeof(*page) + sizeof(*page->elements))) { 1584 ENC_VLOG(enc, "Enclosure Status Page Too Short\n"); 1585 goto out; 1586 } 1587 1588 if (!ses_config_cache_valid(ses_cache, page->hdr.gen_code)) { 1589 ENC_DLOG(enc, "%s: Generation count change detected\n", 1590 __func__); 1591 enc_update_request(enc, SES_UPDATE_GETCONFIG); 1592 goto out; 1593 } 1594 1595 ses_cache_free_status(enc, enc_cache); 1596 ses_cache->status_page = page; 1597 *bufp = NULL; 1598 1599 enc_cache->enc_status = page->hdr.page_specific_flags; 1600 1601 /* 1602 * Read in individual element status. The element order 1603 * matches the order reported in the config page (i.e. the 1604 * order of an unfiltered iteration of the config objects).. 1605 */ 1606 ses_iter_init(enc, enc_cache, &iter); 1607 cur_stat = page->elements; 1608 last_stat = (union ses_status_element *) 1609 &buf[length - sizeof(*last_stat)]; 1610 ENC_DLOG(enc, "%s: total page length %d, xfer_len %d\n", 1611 __func__, length, xfer_len); 1612 while (cur_stat <= last_stat 1613 && (element = ses_iter_next(&iter)) != NULL) { 1614 ENC_DLOG(enc, "%s: obj %d(%d,%d) off=0x%tx status=%jx\n", 1615 __func__, iter.global_element_index, iter.type_index, 1616 iter.type_element_index, (uint8_t *)cur_stat - buf, 1617 scsi_4btoul(cur_stat->bytes)); 1618 1619 memcpy(&element->encstat, cur_stat, sizeof(element->encstat)); 1620 element->svalid = 1; 1621 cur_stat++; 1622 } 1623 1624 if (ses_iter_next(&iter) != NULL) { 1625 ENC_VLOG(enc, "Status page, length insufficient for " 1626 "expected number of objects\n"); 1627 } else { 1628 if (cur_stat <= last_stat) 1629 ENC_VLOG(enc, "Status page, exhausted objects before " 1630 "exhausing page\n"); 1631 enc_update_request(enc, SES_PUBLISH_CACHE); 1632 err = 0; 1633 } 1634 out: 1635 ENC_DLOG(enc, "%s: exiting with error %d\n", __func__, err); 1636 return (err); 1637 } 1638 1639 typedef enum { 1640 /** 1641 * The enclosure should not provide additional element 1642 * status for this element type in page 0x0A. 1643 * 1644 * \note This status is returned for any types not 1645 * listed SES3r02. Further types added in a 1646 * future specification will be incorrectly 1647 * classified. 1648 */ 1649 TYPE_ADDLSTATUS_NONE, 1650 1651 /** 1652 * The element type provides additional element status 1653 * in page 0x0A. 1654 */ 1655 TYPE_ADDLSTATUS_MANDATORY, 1656 1657 /** 1658 * The element type may provide additional element status 1659 * in page 0x0A, but i 1660 */ 1661 TYPE_ADDLSTATUS_OPTIONAL 1662 } ses_addlstatus_avail_t; 1663 1664 /** 1665 * \brief Check to see whether a given type (as obtained via type headers) is 1666 * supported by the additional status command. 1667 * 1668 * \param enc SES softc to check. 1669 * \param typidx Type index to check for. 1670 * 1671 * \return An enumeration indicating if additional status is mandatory, 1672 * optional, or not required for this type. 1673 */ 1674 static ses_addlstatus_avail_t 1675 ses_typehasaddlstatus(enc_softc_t *enc, uint8_t typidx) 1676 { 1677 enc_cache_t *enc_cache; 1678 ses_cache_t *ses_cache; 1679 1680 enc_cache = &enc->enc_daemon_cache; 1681 ses_cache = enc_cache->private; 1682 switch(ses_cache->ses_types[typidx].hdr->etype_elm_type) { 1683 case ELMTYP_DEVICE: 1684 case ELMTYP_ARRAY_DEV: 1685 case ELMTYP_SAS_EXP: 1686 return (TYPE_ADDLSTATUS_MANDATORY); 1687 case ELMTYP_SCSI_INI: 1688 case ELMTYP_SCSI_TGT: 1689 case ELMTYP_ESCC: 1690 return (TYPE_ADDLSTATUS_OPTIONAL); 1691 default: 1692 /* No additional status information available. */ 1693 break; 1694 } 1695 return (TYPE_ADDLSTATUS_NONE); 1696 } 1697 1698 static int ses_get_elm_addlstatus_fc(enc_softc_t *, enc_cache_t *, 1699 uint8_t *, int); 1700 static int ses_get_elm_addlstatus_sas(enc_softc_t *, enc_cache_t *, uint8_t *, 1701 int, int, int, int); 1702 static int ses_get_elm_addlstatus_ata(enc_softc_t *, enc_cache_t *, uint8_t *, 1703 int, int, int, int); 1704 1705 /** 1706 * \brief Parse the additional status element data for each object. 1707 * 1708 * \param enc The SES softc to update. 1709 * \param buf The buffer containing the additional status 1710 * element response. 1711 * \param xfer_len Size of the buffer. 1712 * 1713 * \return 0 on success, errno otherwise. 1714 */ 1715 static int 1716 ses_process_elm_addlstatus(enc_softc_t *enc, struct enc_fsm_state *state, 1717 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1718 { 1719 struct ses_iterator iter, titer; 1720 int eip; 1721 int err; 1722 int length; 1723 int offset; 1724 enc_cache_t *enc_cache; 1725 ses_cache_t *ses_cache; 1726 uint8_t *buf; 1727 ses_element_t *elmpriv; 1728 const struct ses_page_hdr *hdr; 1729 enc_element_t *element, *telement; 1730 1731 enc_cache = &enc->enc_daemon_cache; 1732 ses_cache = enc_cache->private; 1733 buf = *bufp; 1734 err = -1; 1735 1736 if (error != 0) { 1737 err = error; 1738 goto out; 1739 } 1740 ses_cache_free_elm_addlstatus(enc, enc_cache); 1741 ses_cache->elm_addlstatus_page = 1742 (struct ses_addl_elem_status_page *)buf; 1743 *bufp = NULL; 1744 1745 /* 1746 * The objects appear in the same order here as in Enclosure Status, 1747 * which itself is ordered by the Type Descriptors from the Config 1748 * page. However, it is necessary to skip elements that are not 1749 * supported by this page when counting them. 1750 */ 1751 hdr = &ses_cache->elm_addlstatus_page->hdr; 1752 length = ses_page_length(hdr); 1753 ENC_DLOG(enc, "Additional Element Status Page Length 0x%x\n", length); 1754 /* Make sure the length includes at least one header. */ 1755 if (length < sizeof(*hdr)+sizeof(struct ses_elm_addlstatus_base_hdr)) { 1756 ENC_VLOG(enc, "Runt Additional Element Status Page\n"); 1757 goto out; 1758 } 1759 if (length > xfer_len) { 1760 ENC_VLOG(enc, "Additional Element Status Page Too Long\n"); 1761 goto out; 1762 } 1763 1764 if (!ses_config_cache_valid(ses_cache, hdr->gen_code)) { 1765 ENC_DLOG(enc, "%s: Generation count change detected\n", 1766 __func__); 1767 enc_update_request(enc, SES_UPDATE_GETCONFIG); 1768 goto out; 1769 } 1770 1771 offset = sizeof(struct ses_page_hdr); 1772 ses_iter_init(enc, enc_cache, &iter); 1773 while (offset < length 1774 && (element = ses_iter_next(&iter)) != NULL) { 1775 struct ses_elm_addlstatus_base_hdr *elm_hdr; 1776 int proto_info_len; 1777 ses_addlstatus_avail_t status_type; 1778 1779 /* 1780 * Additional element status is only provided for 1781 * individual elements (i.e. overal status elements 1782 * are excluded) and those of the types specified 1783 * in the SES spec. 1784 */ 1785 status_type = ses_typehasaddlstatus(enc, iter.type_index); 1786 if (iter.individual_element_index == ITERATOR_INDEX_INVALID 1787 || status_type == TYPE_ADDLSTATUS_NONE) 1788 continue; 1789 1790 elm_hdr = (struct ses_elm_addlstatus_base_hdr *)&buf[offset]; 1791 eip = ses_elm_addlstatus_eip(elm_hdr); 1792 if (eip) { 1793 struct ses_elm_addlstatus_eip_hdr *eip_hdr; 1794 int expected_index, index; 1795 ses_elem_index_type_t index_type; 1796 1797 eip_hdr = (struct ses_elm_addlstatus_eip_hdr *)elm_hdr; 1798 if (SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2)) { 1799 index_type = SES_ELEM_INDEX_GLOBAL; 1800 expected_index = iter.global_element_index; 1801 } else { 1802 index_type = SES_ELEM_INDEX_INDIVIDUAL; 1803 expected_index = iter.individual_element_index; 1804 } 1805 if (eip_hdr->element_index < expected_index) { 1806 ENC_VLOG(enc, "%s: provided %selement index " 1807 "%d is lower then expected %d\n", 1808 __func__, SES_ADDL_EIP_EIIOE_EI_GLOB( 1809 eip_hdr->byte2) ? "global " : "", 1810 eip_hdr->element_index, expected_index); 1811 goto badindex; 1812 } 1813 titer = iter; 1814 telement = ses_iter_seek_to(&titer, 1815 eip_hdr->element_index, index_type); 1816 if (telement == NULL) { 1817 ENC_VLOG(enc, "%s: provided %selement index " 1818 "%d does not exist\n", __func__, 1819 SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2) ? 1820 "global " : "", eip_hdr->element_index); 1821 goto badindex; 1822 } 1823 if (ses_typehasaddlstatus(enc, titer.type_index) == 1824 TYPE_ADDLSTATUS_NONE) { 1825 ENC_VLOG(enc, "%s: provided %selement index " 1826 "%d can't have additional status\n", 1827 __func__, 1828 SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2) ? 1829 "global " : "", eip_hdr->element_index); 1830 badindex: 1831 /* 1832 * If we expected mandatory element, we may 1833 * guess it was just a wrong index and we may 1834 * use the status. If element was optional, 1835 * then we have no idea where status belongs. 1836 */ 1837 if (status_type == TYPE_ADDLSTATUS_OPTIONAL) 1838 break; 1839 } else { 1840 iter = titer; 1841 element = telement; 1842 } 1843 1844 if (SES_ADDL_EIP_EIIOE_EI_GLOB(eip_hdr->byte2)) 1845 index = iter.global_element_index; 1846 else 1847 index = iter.individual_element_index; 1848 if (index > expected_index 1849 && status_type == TYPE_ADDLSTATUS_MANDATORY) { 1850 ENC_VLOG(enc, "%s: provided %s element" 1851 "index %d skips mandatory status " 1852 " element at index %d\n", 1853 __func__, SES_ADDL_EIP_EIIOE_EI_GLOB( 1854 eip_hdr->byte2) ? "global " : "", 1855 index, expected_index); 1856 } 1857 } 1858 elmpriv = element->elm_private; 1859 ENC_DLOG(enc, "%s: global element index=%d, type index=%d " 1860 "type element index=%d, offset=0x%x, " 1861 "byte0=0x%x, length=0x%x\n", __func__, 1862 iter.global_element_index, iter.type_index, 1863 iter.type_element_index, offset, elm_hdr->byte0, 1864 elm_hdr->length); 1865 1866 /* Skip to after the length field */ 1867 offset += sizeof(struct ses_elm_addlstatus_base_hdr); 1868 1869 /* Make sure the descriptor is within bounds */ 1870 if ((offset + elm_hdr->length) > length) { 1871 ENC_VLOG(enc, "Element %d Beyond End " 1872 "of Additional Element Status Descriptors\n", 1873 iter.global_element_index); 1874 break; 1875 } 1876 1877 /* Skip elements marked as invalid. */ 1878 if (ses_elm_addlstatus_invalid(elm_hdr)) { 1879 offset += elm_hdr->length; 1880 continue; 1881 } 1882 elmpriv->addl.hdr = elm_hdr; 1883 1884 /* Advance to the protocol data, skipping eip bytes if needed */ 1885 offset += (eip * SES_EIP_HDR_EXTRA_LEN); 1886 proto_info_len = elm_hdr->length 1887 - (eip * SES_EIP_HDR_EXTRA_LEN); 1888 1889 /* Errors in this block are ignored as they are non-fatal */ 1890 switch(ses_elm_addlstatus_proto(elm_hdr)) { 1891 case SPSP_PROTO_FC: 1892 if (elm_hdr->length == 0) 1893 break; 1894 ses_get_elm_addlstatus_fc(enc, enc_cache, 1895 &buf[offset], proto_info_len); 1896 break; 1897 case SPSP_PROTO_SAS: 1898 if (elm_hdr->length <= 2) 1899 break; 1900 ses_get_elm_addlstatus_sas(enc, enc_cache, 1901 &buf[offset], 1902 proto_info_len, 1903 eip, iter.type_index, 1904 iter.global_element_index); 1905 break; 1906 case SPSP_PROTO_ATA: 1907 ses_get_elm_addlstatus_ata(enc, enc_cache, 1908 &buf[offset], 1909 proto_info_len, 1910 eip, iter.type_index, 1911 iter.global_element_index); 1912 break; 1913 default: 1914 ENC_VLOG(enc, "Element %d: Unknown Additional Element " 1915 "Protocol 0x%x\n", iter.global_element_index, 1916 ses_elm_addlstatus_proto(elm_hdr)); 1917 break; 1918 } 1919 1920 offset += proto_info_len; 1921 } 1922 err = 0; 1923 out: 1924 if (err) 1925 ses_cache_free_elm_addlstatus(enc, enc_cache); 1926 enc_update_request(enc, SES_PUBLISH_PHYSPATHS); 1927 enc_update_request(enc, SES_PUBLISH_CACHE); 1928 return (err); 1929 } 1930 1931 static int 1932 ses_process_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 1933 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1934 { 1935 ses_softc_t *ses; 1936 1937 ses = enc->enc_private; 1938 /* 1939 * Possible errors: 1940 * o Generation count wrong. 1941 * o Some SCSI status error. 1942 */ 1943 ses_terminate_control_requests(&ses->ses_pending_requests, error); 1944 ses_poll_status(enc); 1945 return (0); 1946 } 1947 1948 static int 1949 ses_publish_physpaths(enc_softc_t *enc, struct enc_fsm_state *state, 1950 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1951 { 1952 struct ses_iterator iter; 1953 enc_cache_t *enc_cache; 1954 enc_element_t *element; 1955 1956 enc_cache = &enc->enc_daemon_cache; 1957 1958 ses_iter_init(enc, enc_cache, &iter); 1959 while ((element = ses_iter_next(&iter)) != NULL) { 1960 /* 1961 * ses_set_physpath() returns success if we changed 1962 * the physpath of any element. This allows us to 1963 * only announce devices once regardless of how 1964 * many times we process additional element status. 1965 */ 1966 if (ses_set_physpath(enc, element, &iter) == 0) 1967 ses_print_addl_data(enc, element); 1968 } 1969 1970 return (0); 1971 } 1972 1973 static int 1974 ses_publish_cache(enc_softc_t *enc, struct enc_fsm_state *state, 1975 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 1976 { 1977 1978 sx_xlock(&enc->enc_cache_lock); 1979 ses_cache_clone(enc, /*src*/&enc->enc_daemon_cache, 1980 /*dst*/&enc->enc_cache); 1981 sx_xunlock(&enc->enc_cache_lock); 1982 1983 return (0); 1984 } 1985 1986 /* 1987 * \brief Sanitize an element descriptor 1988 * 1989 * The SES4r3 standard, sections 3.1.2 and 6.1.10, specifies that element 1990 * descriptors may only contain ASCII characters in the range 0x20 to 0x7e. 1991 * But some vendors violate that rule. Ensure that we only expose compliant 1992 * descriptors to userland. 1993 * 1994 * \param desc SES element descriptor as reported by the hardware 1995 * \param len Length of desc in bytes, not necessarily including 1996 * trailing NUL. It will be modified if desc is invalid. 1997 */ 1998 static const char* 1999 ses_sanitize_elm_desc(const char *desc, uint16_t *len) 2000 { 2001 const char *invalid = "<invalid>"; 2002 int i; 2003 2004 for (i = 0; i < *len; i++) { 2005 if (desc[i] == 0) { 2006 break; 2007 } else if (desc[i] < 0x20 || desc[i] > 0x7e) { 2008 *len = strlen(invalid); 2009 return (invalid); 2010 } 2011 } 2012 return (desc); 2013 } 2014 2015 /** 2016 * \brief Parse the descriptors for each object. 2017 * 2018 * \param enc The SES softc to update. 2019 * \param buf The buffer containing the descriptor list response. 2020 * \param xfer_len Size of the buffer. 2021 * 2022 * \return 0 on success, errno otherwise. 2023 */ 2024 static int 2025 ses_process_elm_descs(enc_softc_t *enc, struct enc_fsm_state *state, 2026 union ccb *ccb, uint8_t **bufp, int error, int xfer_len) 2027 { 2028 ses_softc_t *ses; 2029 struct ses_iterator iter; 2030 enc_element_t *element; 2031 int err; 2032 int offset; 2033 u_long length, plength; 2034 enc_cache_t *enc_cache; 2035 ses_cache_t *ses_cache; 2036 uint8_t *buf; 2037 ses_element_t *elmpriv; 2038 const struct ses_page_hdr *phdr; 2039 const struct ses_elm_desc_hdr *hdr; 2040 2041 ses = enc->enc_private; 2042 enc_cache = &enc->enc_daemon_cache; 2043 ses_cache = enc_cache->private; 2044 buf = *bufp; 2045 err = -1; 2046 2047 if (error != 0) { 2048 err = error; 2049 goto out; 2050 } 2051 ses_cache_free_elm_descs(enc, enc_cache); 2052 ses_cache->elm_descs_page = (struct ses_elem_descr_page *)buf; 2053 *bufp = NULL; 2054 2055 phdr = &ses_cache->elm_descs_page->hdr; 2056 plength = ses_page_length(phdr); 2057 if (xfer_len < sizeof(struct ses_page_hdr)) { 2058 ENC_VLOG(enc, "Runt Element Descriptor Page\n"); 2059 goto out; 2060 } 2061 if (plength > xfer_len) { 2062 ENC_VLOG(enc, "Element Descriptor Page Too Long\n"); 2063 goto out; 2064 } 2065 2066 if (!ses_config_cache_valid(ses_cache, phdr->gen_code)) { 2067 ENC_VLOG(enc, "%s: Generation count change detected\n", 2068 __func__); 2069 enc_update_request(enc, SES_UPDATE_GETCONFIG); 2070 goto out; 2071 } 2072 2073 offset = sizeof(struct ses_page_hdr); 2074 2075 ses_iter_init(enc, enc_cache, &iter); 2076 while (offset < plength 2077 && (element = ses_iter_next(&iter)) != NULL) { 2078 if ((offset + sizeof(struct ses_elm_desc_hdr)) > plength) { 2079 ENC_VLOG(enc, "Element %d Descriptor Header Past " 2080 "End of Buffer\n", iter.global_element_index); 2081 goto out; 2082 } 2083 hdr = (struct ses_elm_desc_hdr *)&buf[offset]; 2084 length = scsi_2btoul(hdr->length); 2085 ENC_DLOG(enc, "%s: obj %d(%d,%d) length=%d off=%d\n", __func__, 2086 iter.global_element_index, iter.type_index, 2087 iter.type_element_index, length, offset); 2088 if ((offset + sizeof(*hdr) + length) > plength) { 2089 ENC_VLOG(enc, "Element%d Descriptor Past " 2090 "End of Buffer\n", iter.global_element_index); 2091 goto out; 2092 } 2093 offset += sizeof(*hdr); 2094 2095 if (length > 0) { 2096 elmpriv = element->elm_private; 2097 elmpriv->descr_len = length; 2098 elmpriv->descr = ses_sanitize_elm_desc(&buf[offset], 2099 &elmpriv->descr_len); 2100 } 2101 2102 /* skip over the descriptor itself */ 2103 offset += length; 2104 } 2105 2106 err = 0; 2107 out: 2108 if (err == 0) { 2109 if (ses->ses_flags & SES_FLAG_ADDLSTATUS) 2110 enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS); 2111 } 2112 enc_update_request(enc, SES_PUBLISH_CACHE); 2113 return (err); 2114 } 2115 2116 static int 2117 ses_fill_rcv_diag_io(enc_softc_t *enc, struct enc_fsm_state *state, 2118 union ccb *ccb, uint8_t *buf) 2119 { 2120 2121 if (enc->enc_type == ENC_SEMB_SES) { 2122 semb_receive_diagnostic_results(&ccb->ataio, /*retries*/5, 2123 NULL, MSG_SIMPLE_Q_TAG, /*pcv*/1, 2124 state->page_code, buf, state->buf_size, 2125 state->timeout); 2126 } else { 2127 scsi_receive_diagnostic_results(&ccb->csio, /*retries*/5, 2128 NULL, MSG_SIMPLE_Q_TAG, /*pcv*/1, 2129 state->page_code, buf, state->buf_size, 2130 SSD_FULL_SIZE, state->timeout); 2131 } 2132 return (0); 2133 } 2134 2135 /** 2136 * \brief Encode the object status into the response buffer, which is 2137 * expected to contain the current enclosure status. This function 2138 * turns off all the 'select' bits for the objects except for the 2139 * object specified, then sends it back to the enclosure. 2140 * 2141 * \param enc SES enclosure the change is being applied to. 2142 * \param buf Buffer containing the current enclosure status response. 2143 * \param amt Length of the response in the buffer. 2144 * \param req The control request to be applied to buf. 2145 * 2146 * \return 0 on success, errno otherwise. 2147 */ 2148 static int 2149 ses_encode(enc_softc_t *enc, uint8_t *buf, int amt, ses_control_request_t *req) 2150 { 2151 struct ses_iterator iter; 2152 enc_element_t *element; 2153 int offset; 2154 struct ses_control_page_hdr *hdr; 2155 2156 ses_iter_init(enc, &enc->enc_cache, &iter); 2157 hdr = (struct ses_control_page_hdr *)buf; 2158 if (req->elm_idx == -1) { 2159 /* for enclosure status, at least 2 bytes are needed */ 2160 if (amt < 2) 2161 return EIO; 2162 hdr->control_flags = 2163 req->elm_stat.comstatus & SES_SET_STATUS_MASK; 2164 ENC_DLOG(enc, "Set EncStat %x\n", hdr->control_flags); 2165 return (0); 2166 } 2167 2168 element = ses_iter_seek_to(&iter, req->elm_idx, SES_ELEM_INDEX_GLOBAL); 2169 if (element == NULL) 2170 return (ENXIO); 2171 2172 /* 2173 * Seek to the type set that corresponds to the requested object. 2174 * The +1 is for the overall status element for the type. 2175 */ 2176 offset = sizeof(struct ses_control_page_hdr) 2177 + (iter.global_element_index * sizeof(struct ses_comstat)); 2178 2179 /* Check for buffer overflow. */ 2180 if (offset + sizeof(struct ses_comstat) > amt) 2181 return (EIO); 2182 2183 /* Set the status. */ 2184 memcpy(&buf[offset], &req->elm_stat, sizeof(struct ses_comstat)); 2185 2186 ENC_DLOG(enc, "Set Type 0x%x Obj 0x%x (offset %d) with %x %x %x %x\n", 2187 iter.type_index, iter.global_element_index, offset, 2188 req->elm_stat.comstatus, req->elm_stat.comstat[0], 2189 req->elm_stat.comstat[1], req->elm_stat.comstat[2]); 2190 2191 return (0); 2192 } 2193 2194 static int 2195 ses_fill_control_request(enc_softc_t *enc, struct enc_fsm_state *state, 2196 union ccb *ccb, uint8_t *buf) 2197 { 2198 ses_softc_t *ses; 2199 enc_cache_t *enc_cache; 2200 ses_cache_t *ses_cache; 2201 struct ses_control_page_hdr *hdr; 2202 ses_control_request_t *req; 2203 size_t plength; 2204 size_t offset; 2205 2206 ses = enc->enc_private; 2207 enc_cache = &enc->enc_daemon_cache; 2208 ses_cache = enc_cache->private; 2209 hdr = (struct ses_control_page_hdr *)buf; 2210 2211 if (ses_cache->status_page == NULL) { 2212 ses_terminate_control_requests(&ses->ses_requests, EIO); 2213 return (EIO); 2214 } 2215 2216 plength = ses_page_length(&ses_cache->status_page->hdr); 2217 memcpy(buf, ses_cache->status_page, plength); 2218 2219 /* Disable the select bits in all status entries. */ 2220 offset = sizeof(struct ses_control_page_hdr); 2221 for (offset = sizeof(struct ses_control_page_hdr); 2222 offset < plength; offset += sizeof(struct ses_comstat)) { 2223 buf[offset] &= ~SESCTL_CSEL; 2224 } 2225 2226 /* And make sure the INVOP bit is clear. */ 2227 hdr->control_flags &= ~SES_ENCSTAT_INVOP; 2228 2229 /* Apply incoming requests. */ 2230 while ((req = TAILQ_FIRST(&ses->ses_requests)) != NULL) { 2231 TAILQ_REMOVE(&ses->ses_requests, req, links); 2232 req->result = ses_encode(enc, buf, plength, req); 2233 if (req->result != 0) { 2234 wakeup(req); 2235 continue; 2236 } 2237 TAILQ_INSERT_TAIL(&ses->ses_pending_requests, req, links); 2238 } 2239 2240 if (TAILQ_EMPTY(&ses->ses_pending_requests) != 0) 2241 return (ENOENT); 2242 2243 /* Fill out the ccb */ 2244 if (enc->enc_type == ENC_SEMB_SES) { 2245 semb_send_diagnostic(&ccb->ataio, /*retries*/5, NULL, 2246 MSG_SIMPLE_Q_TAG, 2247 buf, ses_page_length(&ses_cache->status_page->hdr), 2248 state->timeout); 2249 } else { 2250 scsi_send_diagnostic(&ccb->csio, /*retries*/5, NULL, 2251 MSG_SIMPLE_Q_TAG, /*unit_offline*/0, 2252 /*device_offline*/0, /*self_test*/0, 2253 /*page_format*/1, /*self_test_code*/0, 2254 buf, ses_page_length(&ses_cache->status_page->hdr), 2255 SSD_FULL_SIZE, state->timeout); 2256 } 2257 return (0); 2258 } 2259 2260 static int 2261 ses_get_elm_addlstatus_fc(enc_softc_t *enc, enc_cache_t *enc_cache, 2262 uint8_t *buf, int bufsiz) 2263 { 2264 ENC_VLOG(enc, "FC Device Support Stubbed in Additional Status Page\n"); 2265 return (ENODEV); 2266 } 2267 2268 #define SES_PRINT_PORTS(p, type) do { \ 2269 if (((p) & SES_SASOBJ_DEV_PHY_PROTOMASK) != 0) { \ 2270 sbuf_printf(sbp, " %s (", type); \ 2271 if ((p) & SES_SASOBJ_DEV_PHY_SMP) \ 2272 sbuf_printf(sbp, " SMP"); \ 2273 if ((p) & SES_SASOBJ_DEV_PHY_STP) \ 2274 sbuf_printf(sbp, " STP"); \ 2275 if ((p) & SES_SASOBJ_DEV_PHY_SSP) \ 2276 sbuf_printf(sbp, " SSP"); \ 2277 sbuf_printf(sbp, " )"); \ 2278 } \ 2279 } while(0) 2280 2281 /** 2282 * \brief Print the additional element status data for this object, for SAS 2283 * type 0 objects. See SES2 r20 Section 6.1.13.3.2. 2284 * 2285 * \param sesname SES device name associated with the object. 2286 * \param sbp Sbuf to print to. 2287 * \param obj The object to print the data for. 2288 */ 2289 static void 2290 ses_print_addl_data_sas_type0(char *sesname, struct sbuf *sbp, 2291 enc_element_t *obj) 2292 { 2293 int i; 2294 ses_element_t *elmpriv; 2295 struct ses_addl_status *addl; 2296 struct ses_elm_sas_device_phy *phy; 2297 2298 elmpriv = obj->elm_private; 2299 addl = &(elmpriv->addl); 2300 sbuf_printf(sbp, ", SAS Slot: %d%s phys", 2301 addl->proto_hdr.sas->base_hdr.num_phys, 2302 ses_elm_sas_type0_not_all_phys(addl->proto_hdr.sas) ? "+" : ""); 2303 if (ses_elm_addlstatus_eip(addl->hdr)) 2304 sbuf_printf(sbp, " at slot %d", 2305 addl->proto_hdr.sas->type0_eip.dev_slot_num); 2306 sbuf_printf(sbp, "\n"); 2307 if (addl->proto_data.sasdev_phys == NULL) 2308 return; 2309 for (i = 0;i < addl->proto_hdr.sas->base_hdr.num_phys;i++) { 2310 phy = &addl->proto_data.sasdev_phys[i]; 2311 sbuf_printf(sbp, "%s: phy %d:", sesname, i); 2312 if (ses_elm_sas_dev_phy_sata_dev(phy)) 2313 /* Spec says all other fields are specific values */ 2314 sbuf_printf(sbp, " SATA device\n"); 2315 else { 2316 sbuf_printf(sbp, " SAS device type %d phy %d", 2317 ses_elm_sas_dev_phy_dev_type(phy), phy->phy_id); 2318 SES_PRINT_PORTS(phy->initiator_ports, "Initiator"); 2319 SES_PRINT_PORTS(phy->target_ports, "Target"); 2320 sbuf_printf(sbp, "\n"); 2321 } 2322 sbuf_printf(sbp, "%s: phy %d: parent %jx addr %jx\n", 2323 sesname, i, 2324 (uintmax_t)scsi_8btou64(phy->parent_addr), 2325 (uintmax_t)scsi_8btou64(phy->phy_addr)); 2326 } 2327 } 2328 #undef SES_PRINT_PORTS 2329 2330 /** 2331 * \brief Print the additional element status data for this object, for SAS 2332 * type 1 objects. See SES2 r20 Sections 6.1.13.3.3 and 6.1.13.3.4. 2333 * 2334 * \param sesname SES device name associated with the object. 2335 * \param sbp Sbuf to print to. 2336 * \param obj The object to print the data for. 2337 */ 2338 static void 2339 ses_print_addl_data_sas_type1(char *sesname, struct sbuf *sbp, 2340 enc_element_t *obj) 2341 { 2342 int i, num_phys; 2343 ses_element_t *elmpriv; 2344 struct ses_addl_status *addl; 2345 struct ses_elm_sas_expander_phy *exp_phy; 2346 struct ses_elm_sas_port_phy *port_phy; 2347 2348 elmpriv = obj->elm_private; 2349 addl = &(elmpriv->addl); 2350 sbuf_printf(sbp, ", SAS "); 2351 if (obj->elm_type == ELMTYP_SAS_EXP) { 2352 num_phys = addl->proto_hdr.sas->base_hdr.num_phys; 2353 sbuf_printf(sbp, "Expander: %d phys", num_phys); 2354 if (addl->proto_data.sasexp_phys == NULL) 2355 return; 2356 for (i = 0;i < num_phys;i++) { 2357 exp_phy = &addl->proto_data.sasexp_phys[i]; 2358 sbuf_printf(sbp, "%s: phy %d: connector %d other %d\n", 2359 sesname, i, exp_phy->connector_index, 2360 exp_phy->other_index); 2361 } 2362 } else { 2363 num_phys = addl->proto_hdr.sas->base_hdr.num_phys; 2364 sbuf_printf(sbp, "Port: %d phys", num_phys); 2365 if (addl->proto_data.sasport_phys == NULL) 2366 return; 2367 for (i = 0;i < num_phys;i++) { 2368 port_phy = &addl->proto_data.sasport_phys[i]; 2369 sbuf_printf(sbp, 2370 "%s: phy %d: id %d connector %d other %d\n", 2371 sesname, i, port_phy->phy_id, 2372 port_phy->connector_index, port_phy->other_index); 2373 sbuf_printf(sbp, "%s: phy %d: addr %jx\n", sesname, i, 2374 (uintmax_t)scsi_8btou64(port_phy->phy_addr)); 2375 } 2376 } 2377 } 2378 2379 /** 2380 * \brief Print the additional element status data for this object, for 2381 * ATA objects. 2382 * 2383 * \param sbp Sbuf to print to. 2384 * \param obj The object to print the data for. 2385 */ 2386 static void 2387 ses_print_addl_data_ata(struct sbuf *sbp, enc_element_t *obj) 2388 { 2389 ses_element_t *elmpriv = obj->elm_private; 2390 struct ses_addl_status *addl = &elmpriv->addl; 2391 struct ses_elm_ata_hdr *ata = addl->proto_hdr.ata; 2392 2393 sbuf_printf(sbp, ", SATA Slot: scbus%d target %d\n", 2394 scsi_4btoul(ata->bus), scsi_4btoul(ata->target)); 2395 } 2396 2397 /** 2398 * \brief Print the additional element status data for this object. 2399 * 2400 * \param enc SES softc associated with the object. 2401 * \param obj The object to print the data for. 2402 */ 2403 static void 2404 ses_print_addl_data(enc_softc_t *enc, enc_element_t *obj) 2405 { 2406 ses_element_t *elmpriv; 2407 struct ses_addl_status *addl; 2408 struct sbuf sesname, name, out; 2409 2410 elmpriv = obj->elm_private; 2411 if (elmpriv == NULL) 2412 return; 2413 2414 addl = &(elmpriv->addl); 2415 if (addl->hdr == NULL) 2416 return; 2417 2418 sbuf_new(&sesname, NULL, 16, SBUF_AUTOEXTEND); 2419 sbuf_new(&name, NULL, 16, SBUF_AUTOEXTEND); 2420 sbuf_new(&out, NULL, 512, SBUF_AUTOEXTEND); 2421 ses_paths_iter(enc, obj, ses_elmdevname_callback, &name); 2422 if (sbuf_len(&name) == 0) 2423 sbuf_printf(&name, "(none)"); 2424 sbuf_finish(&name); 2425 sbuf_printf(&sesname, "%s%d", enc->periph->periph_name, 2426 enc->periph->unit_number); 2427 sbuf_finish(&sesname); 2428 sbuf_printf(&out, "%s: %s in ", sbuf_data(&sesname), sbuf_data(&name)); 2429 if (elmpriv->descr != NULL) 2430 sbuf_printf(&out, "'%s'", elmpriv->descr); 2431 else { 2432 if (obj->elm_type <= ELMTYP_LAST) 2433 sbuf_cat(&out, elm_type_names[obj->elm_type]); 2434 else 2435 sbuf_printf(&out, "<Type 0x%02x>", obj->elm_type); 2436 sbuf_printf(&out, " %d", obj->type_elm_idx); 2437 if (obj->subenclosure != 0) 2438 sbuf_printf(&out, " of subenc %d", obj->subenclosure); 2439 } 2440 switch(ses_elm_addlstatus_proto(addl->hdr)) { 2441 case SPSP_PROTO_FC: 2442 goto noaddl; /* stubbed for now */ 2443 case SPSP_PROTO_SAS: 2444 if (addl->proto_hdr.sas == NULL) 2445 goto noaddl; 2446 switch(ses_elm_sas_descr_type(addl->proto_hdr.sas)) { 2447 case SES_SASOBJ_TYPE_SLOT: 2448 ses_print_addl_data_sas_type0(sbuf_data(&sesname), 2449 &out, obj); 2450 break; 2451 case SES_SASOBJ_TYPE_OTHER: 2452 ses_print_addl_data_sas_type1(sbuf_data(&sesname), 2453 &out, obj); 2454 break; 2455 default: 2456 goto noaddl; 2457 } 2458 break; 2459 case SPSP_PROTO_ATA: 2460 if (addl->proto_hdr.ata == NULL) 2461 goto noaddl; 2462 ses_print_addl_data_ata(&out, obj); 2463 break; 2464 default: 2465 noaddl: 2466 sbuf_cat(&out, "\n"); 2467 break; 2468 } 2469 sbuf_finish(&out); 2470 printf("%s", sbuf_data(&out)); 2471 sbuf_delete(&out); 2472 sbuf_delete(&name); 2473 sbuf_delete(&sesname); 2474 } 2475 2476 /** 2477 * \brief Update the softc with the additional element status data for this 2478 * object, for SAS type 0 objects. 2479 * 2480 * \param enc SES softc to be updated. 2481 * \param buf The additional element status response buffer. 2482 * \param bufsiz Size of the response buffer. 2483 * \param eip The EIP bit value. 2484 * \param nobj Number of objects attached to the SES softc. 2485 * 2486 * \return 0 on success, errno otherwise. 2487 */ 2488 static int 2489 ses_get_elm_addlstatus_sas_type0(enc_softc_t *enc, enc_cache_t *enc_cache, 2490 uint8_t *buf, int bufsiz, int eip, int nobj) 2491 { 2492 int err, offset, physz; 2493 enc_element_t *obj; 2494 ses_element_t *elmpriv; 2495 struct ses_addl_status *addl; 2496 2497 err = offset = 0; 2498 2499 /* basic object setup */ 2500 obj = &(enc_cache->elm_map[nobj]); 2501 elmpriv = obj->elm_private; 2502 addl = &(elmpriv->addl); 2503 2504 addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset]; 2505 2506 /* Don't assume this object has any phys */ 2507 bzero(&addl->proto_data, sizeof(addl->proto_data)); 2508 if (addl->proto_hdr.sas->base_hdr.num_phys == 0) 2509 goto out; 2510 2511 /* Skip forward to the phy list */ 2512 if (eip) 2513 offset += sizeof(struct ses_elm_sas_type0_eip_hdr); 2514 else 2515 offset += sizeof(struct ses_elm_sas_type0_base_hdr); 2516 2517 /* Make sure the phy list fits in the buffer */ 2518 physz = addl->proto_hdr.sas->base_hdr.num_phys; 2519 physz *= sizeof(struct ses_elm_sas_device_phy); 2520 if (physz > (bufsiz - offset + 4)) { 2521 ENC_VLOG(enc, "Element %d Device Phy List Beyond End Of Buffer\n", 2522 nobj); 2523 err = EIO; 2524 goto out; 2525 } 2526 2527 /* Point to the phy list */ 2528 addl->proto_data.sasdev_phys = 2529 (struct ses_elm_sas_device_phy *)&buf[offset]; 2530 2531 out: 2532 return (err); 2533 } 2534 2535 /** 2536 * \brief Update the softc with the additional element status data for this 2537 * object, for SAS type 1 objects. 2538 * 2539 * \param enc SES softc to be updated. 2540 * \param buf The additional element status response buffer. 2541 * \param bufsiz Size of the response buffer. 2542 * \param eip The EIP bit value. 2543 * \param nobj Number of objects attached to the SES softc. 2544 * 2545 * \return 0 on success, errno otherwise. 2546 */ 2547 static int 2548 ses_get_elm_addlstatus_sas_type1(enc_softc_t *enc, enc_cache_t *enc_cache, 2549 uint8_t *buf, int bufsiz, int eip, int nobj) 2550 { 2551 int err, offset, physz; 2552 enc_element_t *obj; 2553 ses_element_t *elmpriv; 2554 struct ses_addl_status *addl; 2555 2556 err = offset = 0; 2557 2558 /* basic object setup */ 2559 obj = &(enc_cache->elm_map[nobj]); 2560 elmpriv = obj->elm_private; 2561 addl = &(elmpriv->addl); 2562 2563 addl->proto_hdr.sas = (union ses_elm_sas_hdr *)&buf[offset]; 2564 2565 /* Don't assume this object has any phys */ 2566 bzero(&addl->proto_data, sizeof(addl->proto_data)); 2567 if (addl->proto_hdr.sas->base_hdr.num_phys == 0) 2568 goto out; 2569 2570 /* Process expanders differently from other type1 cases */ 2571 if (obj->elm_type == ELMTYP_SAS_EXP) { 2572 offset += sizeof(struct ses_elm_sas_type1_expander_hdr); 2573 physz = addl->proto_hdr.sas->base_hdr.num_phys * 2574 sizeof(struct ses_elm_sas_expander_phy); 2575 if (physz > (bufsiz - offset)) { 2576 ENC_VLOG(enc, "Element %d: Expander Phy List Beyond " 2577 "End Of Buffer\n", nobj); 2578 err = EIO; 2579 goto out; 2580 } 2581 addl->proto_data.sasexp_phys = 2582 (struct ses_elm_sas_expander_phy *)&buf[offset]; 2583 } else { 2584 offset += sizeof(struct ses_elm_sas_type1_nonexpander_hdr); 2585 physz = addl->proto_hdr.sas->base_hdr.num_phys * 2586 sizeof(struct ses_elm_sas_port_phy); 2587 if (physz > (bufsiz - offset + 4)) { 2588 ENC_VLOG(enc, "Element %d: Port Phy List Beyond End " 2589 "Of Buffer\n", nobj); 2590 err = EIO; 2591 goto out; 2592 } 2593 addl->proto_data.sasport_phys = 2594 (struct ses_elm_sas_port_phy *)&buf[offset]; 2595 } 2596 2597 out: 2598 return (err); 2599 } 2600 2601 /** 2602 * \brief Update the softc with the additional element status data for this 2603 * object, for SAS objects. 2604 * 2605 * \param enc SES softc to be updated. 2606 * \param buf The additional element status response buffer. 2607 * \param bufsiz Size of the response buffer. 2608 * \param eip The EIP bit value. 2609 * \param tidx Type index for this object. 2610 * \param nobj Number of objects attached to the SES softc. 2611 * 2612 * \return 0 on success, errno otherwise. 2613 */ 2614 static int 2615 ses_get_elm_addlstatus_sas(enc_softc_t *enc, enc_cache_t *enc_cache, 2616 uint8_t *buf, int bufsiz, int eip, int tidx, 2617 int nobj) 2618 { 2619 int dtype, err; 2620 ses_cache_t *ses_cache; 2621 union ses_elm_sas_hdr *hdr; 2622 2623 /* Need to be able to read the descriptor type! */ 2624 if (bufsiz < sizeof(union ses_elm_sas_hdr)) { 2625 err = EIO; 2626 goto out; 2627 } 2628 2629 ses_cache = enc_cache->private; 2630 2631 hdr = (union ses_elm_sas_hdr *)buf; 2632 dtype = ses_elm_sas_descr_type(hdr); 2633 switch(dtype) { 2634 case SES_SASOBJ_TYPE_SLOT: 2635 switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { 2636 case ELMTYP_DEVICE: 2637 case ELMTYP_ARRAY_DEV: 2638 break; 2639 default: 2640 ENC_VLOG(enc, "Element %d has Additional Status type 0, " 2641 "invalid for SES element type 0x%x\n", nobj, 2642 ses_cache->ses_types[tidx].hdr->etype_elm_type); 2643 err = ENODEV; 2644 goto out; 2645 } 2646 err = ses_get_elm_addlstatus_sas_type0(enc, enc_cache, 2647 buf, bufsiz, eip, 2648 nobj); 2649 break; 2650 case SES_SASOBJ_TYPE_OTHER: 2651 switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { 2652 case ELMTYP_SAS_EXP: 2653 case ELMTYP_SCSI_INI: 2654 case ELMTYP_SCSI_TGT: 2655 case ELMTYP_ESCC: 2656 break; 2657 default: 2658 ENC_VLOG(enc, "Element %d has Additional Status type 1, " 2659 "invalid for SES element type 0x%x\n", nobj, 2660 ses_cache->ses_types[tidx].hdr->etype_elm_type); 2661 err = ENODEV; 2662 goto out; 2663 } 2664 err = ses_get_elm_addlstatus_sas_type1(enc, enc_cache, buf, 2665 bufsiz, eip, nobj); 2666 break; 2667 default: 2668 ENC_VLOG(enc, "Element %d of type 0x%x has Additional Status " 2669 "of unknown type 0x%x\n", nobj, 2670 ses_cache->ses_types[tidx].hdr->etype_elm_type, dtype); 2671 err = ENODEV; 2672 break; 2673 } 2674 2675 out: 2676 return (err); 2677 } 2678 2679 /** 2680 * \brief Update the softc with the additional element status data for this 2681 * object, for ATA objects. 2682 * 2683 * \param enc SES softc to be updated. 2684 * \param buf The additional element status response buffer. 2685 * \param bufsiz Size of the response buffer. 2686 * \param eip The EIP bit value. 2687 * \param tidx Type index for this object. 2688 * \param nobj Number of objects attached to the SES softc. 2689 * 2690 * \return 0 on success, errno otherwise. 2691 */ 2692 static int 2693 ses_get_elm_addlstatus_ata(enc_softc_t *enc, enc_cache_t *enc_cache, 2694 uint8_t *buf, int bufsiz, int eip, int tidx, 2695 int nobj) 2696 { 2697 int err; 2698 ses_cache_t *ses_cache; 2699 2700 if (bufsiz < sizeof(struct ses_elm_ata_hdr)) { 2701 err = EIO; 2702 goto out; 2703 } 2704 2705 ses_cache = enc_cache->private; 2706 switch(ses_cache->ses_types[tidx].hdr->etype_elm_type) { 2707 case ELMTYP_DEVICE: 2708 case ELMTYP_ARRAY_DEV: 2709 break; 2710 default: 2711 ENC_VLOG(enc, "Element %d has Additional Status, " 2712 "invalid for SES element type 0x%x\n", nobj, 2713 ses_cache->ses_types[tidx].hdr->etype_elm_type); 2714 err = ENODEV; 2715 goto out; 2716 } 2717 2718 ((ses_element_t *)enc_cache->elm_map[nobj].elm_private) 2719 ->addl.proto_hdr.ata = (struct ses_elm_ata_hdr *)buf; 2720 err = 0; 2721 2722 out: 2723 return (err); 2724 } 2725 2726 static void 2727 ses_softc_invalidate(enc_softc_t *enc) 2728 { 2729 ses_softc_t *ses; 2730 2731 ses = enc->enc_private; 2732 ses_terminate_control_requests(&ses->ses_requests, ENXIO); 2733 } 2734 2735 static void 2736 ses_softc_cleanup(enc_softc_t *enc) 2737 { 2738 2739 ses_cache_free(enc, &enc->enc_cache); 2740 ses_cache_free(enc, &enc->enc_daemon_cache); 2741 ENC_FREE_AND_NULL(enc->enc_private); 2742 ENC_FREE_AND_NULL(enc->enc_cache.private); 2743 ENC_FREE_AND_NULL(enc->enc_daemon_cache.private); 2744 } 2745 2746 static int 2747 ses_init_enc(enc_softc_t *enc) 2748 { 2749 return (0); 2750 } 2751 2752 static int 2753 ses_set_enc_status(enc_softc_t *enc, uint8_t encstat, int slpflag) 2754 { 2755 ses_control_request_t req; 2756 ses_softc_t *ses; 2757 2758 ses = enc->enc_private; 2759 req.elm_idx = SES_SETSTATUS_ENC_IDX; 2760 req.elm_stat.comstatus = encstat & 0xf; 2761 2762 TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links); 2763 enc_update_request(enc, SES_PROCESS_CONTROL_REQS); 2764 cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 2765 2766 return (req.result); 2767 } 2768 2769 static int 2770 ses_get_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag) 2771 { 2772 unsigned int i = elms->elm_idx; 2773 2774 memcpy(elms->cstat, &enc->enc_cache.elm_map[i].encstat, 4); 2775 return (0); 2776 } 2777 2778 static int 2779 ses_set_elm_status(enc_softc_t *enc, encioc_elm_status_t *elms, int slpflag) 2780 { 2781 ses_control_request_t req; 2782 ses_softc_t *ses; 2783 2784 /* If this is clear, we don't do diddly. */ 2785 if ((elms->cstat[0] & SESCTL_CSEL) == 0) 2786 return (0); 2787 2788 ses = enc->enc_private; 2789 req.elm_idx = elms->elm_idx; 2790 memcpy(&req.elm_stat, elms->cstat, sizeof(req.elm_stat)); 2791 2792 TAILQ_INSERT_TAIL(&ses->ses_requests, &req, links); 2793 enc_update_request(enc, SES_PROCESS_CONTROL_REQS); 2794 cam_periph_sleep(enc->periph, &req, PUSER, "encstat", 0); 2795 2796 return (req.result); 2797 } 2798 2799 static int 2800 ses_get_elm_desc(enc_softc_t *enc, encioc_elm_desc_t *elmd) 2801 { 2802 int i = (int)elmd->elm_idx; 2803 ses_element_t *elmpriv; 2804 2805 /* Assume caller has already checked obj_id validity */ 2806 elmpriv = enc->enc_cache.elm_map[i].elm_private; 2807 /* object might not have a descriptor */ 2808 if (elmpriv == NULL || elmpriv->descr == NULL) { 2809 elmd->elm_desc_len = 0; 2810 return (0); 2811 } 2812 if (elmd->elm_desc_len > elmpriv->descr_len) 2813 elmd->elm_desc_len = elmpriv->descr_len; 2814 copyout(elmpriv->descr, elmd->elm_desc_str, elmd->elm_desc_len); 2815 return (0); 2816 } 2817 2818 /** 2819 * \brief Respond to ENCIOC_GETELMDEVNAME, providing a device name for the 2820 * given object id if one is available. 2821 * 2822 * \param enc SES softc to examine. 2823 * \param objdn ioctl structure to read/write device name info. 2824 * 2825 * \return 0 on success, errno otherwise. 2826 */ 2827 static int 2828 ses_get_elm_devnames(enc_softc_t *enc, encioc_elm_devnames_t *elmdn) 2829 { 2830 struct sbuf sb; 2831 int len; 2832 2833 len = elmdn->elm_names_size; 2834 if (len < 0) 2835 return (EINVAL); 2836 2837 cam_periph_unlock(enc->periph); 2838 sbuf_new(&sb, NULL, len, SBUF_FIXEDLEN); 2839 ses_paths_iter(enc, &enc->enc_cache.elm_map[elmdn->elm_idx], 2840 ses_elmdevname_callback, &sb); 2841 sbuf_finish(&sb); 2842 elmdn->elm_names_len = sbuf_len(&sb); 2843 copyout(sbuf_data(&sb), elmdn->elm_devnames, elmdn->elm_names_len + 1); 2844 sbuf_delete(&sb); 2845 cam_periph_lock(enc->periph); 2846 return (elmdn->elm_names_len > 0 ? 0 : ENODEV); 2847 } 2848 2849 /** 2850 * \brief Send a string to the primary subenclosure using the String Out 2851 * SES diagnostic page. 2852 * 2853 * \param enc SES enclosure to run the command on. 2854 * \param sstr SES string structure to operate on 2855 * \param ioc Ioctl being performed 2856 * 2857 * \return 0 on success, errno otherwise. 2858 */ 2859 static int 2860 ses_handle_string(enc_softc_t *enc, encioc_string_t *sstr, unsigned long ioc) 2861 { 2862 enc_cache_t *enc_cache; 2863 ses_cache_t *ses_cache; 2864 const struct ses_enc_desc *enc_desc; 2865 int amt, payload, ret; 2866 char cdb[6]; 2867 char str[32]; 2868 char vendor[9]; 2869 char product[17]; 2870 char rev[5]; 2871 uint8_t *buf; 2872 size_t size, rsize; 2873 2874 enc_cache = &enc->enc_daemon_cache; 2875 ses_cache = enc_cache->private; 2876 2877 /* Implement SES2r20 6.1.6 */ 2878 if (sstr->bufsiz > ENC_STRING_MAX) 2879 return (EINVAL); /* buffer size too large */ 2880 2881 switch (ioc) { 2882 case ENCIOC_SETSTRING: 2883 payload = sstr->bufsiz + 4; /* header for SEND DIAGNOSTIC */ 2884 amt = 0 - payload; 2885 buf = ENC_MALLOC(payload); 2886 if (buf == NULL) 2887 return (ENOMEM); 2888 ses_page_cdb(cdb, payload, 0, CAM_DIR_OUT); 2889 /* Construct the page request */ 2890 buf[0] = SesStringOut; 2891 buf[1] = 0; 2892 buf[2] = sstr->bufsiz >> 8; 2893 buf[3] = sstr->bufsiz & 0xff; 2894 ret = copyin(sstr->buf, &buf[4], sstr->bufsiz); 2895 if (ret != 0) { 2896 ENC_FREE(buf); 2897 return (ret); 2898 } 2899 break; 2900 case ENCIOC_GETSTRING: 2901 payload = sstr->bufsiz; 2902 amt = payload; 2903 buf = ENC_MALLOC(payload); 2904 if (buf == NULL) 2905 return (ENOMEM); 2906 ses_page_cdb(cdb, payload, SesStringIn, CAM_DIR_IN); 2907 break; 2908 case ENCIOC_GETENCNAME: 2909 if (ses_cache->ses_nsubencs < 1) 2910 return (ENODEV); 2911 enc_desc = ses_cache->subencs[0]; 2912 cam_strvis(vendor, enc_desc->vendor_id, 2913 sizeof(enc_desc->vendor_id), sizeof(vendor)); 2914 cam_strvis(product, enc_desc->product_id, 2915 sizeof(enc_desc->product_id), sizeof(product)); 2916 cam_strvis(rev, enc_desc->product_rev, 2917 sizeof(enc_desc->product_rev), sizeof(rev)); 2918 rsize = snprintf(str, sizeof(str), "%s %s %s", 2919 vendor, product, rev) + 1; 2920 if (rsize > sizeof(str)) 2921 rsize = sizeof(str); 2922 size = rsize; 2923 if (size > sstr->bufsiz) 2924 size = sstr->bufsiz; 2925 copyout(str, sstr->buf, size); 2926 sstr->bufsiz = rsize; 2927 return (size == rsize ? 0 : ENOMEM); 2928 case ENCIOC_GETENCID: 2929 if (ses_cache->ses_nsubencs < 1) 2930 return (ENODEV); 2931 enc_desc = ses_cache->subencs[0]; 2932 rsize = snprintf(str, sizeof(str), "%16jx", 2933 scsi_8btou64(enc_desc->logical_id)) + 1; 2934 if (rsize > sizeof(str)) 2935 rsize = sizeof(str); 2936 size = rsize; 2937 if (size > sstr->bufsiz) 2938 size = sstr->bufsiz; 2939 copyout(str, sstr->buf, size); 2940 sstr->bufsiz = rsize; 2941 return (size == rsize ? 0 : ENOMEM); 2942 default: 2943 return (EINVAL); 2944 } 2945 ret = enc_runcmd(enc, cdb, 6, buf, &amt); 2946 if (ret == 0 && ioc == ENCIOC_GETSTRING) 2947 ret = copyout(buf, sstr->buf, sstr->bufsiz); 2948 if (ioc == ENCIOC_SETSTRING || ioc == ENCIOC_GETSTRING) 2949 ENC_FREE(buf); 2950 return (ret); 2951 } 2952 2953 /** 2954 * \invariant Called with cam_periph mutex held. 2955 */ 2956 static void 2957 ses_poll_status(enc_softc_t *enc) 2958 { 2959 ses_softc_t *ses; 2960 2961 ses = enc->enc_private; 2962 enc_update_request(enc, SES_UPDATE_GETSTATUS); 2963 if (ses->ses_flags & SES_FLAG_DESC) 2964 enc_update_request(enc, SES_UPDATE_GETELMDESCS); 2965 if (ses->ses_flags & SES_FLAG_ADDLSTATUS) 2966 enc_update_request(enc, SES_UPDATE_GETELMADDLSTATUS); 2967 } 2968 2969 /** 2970 * \brief Notification received when CAM detects a new device in the 2971 * SCSI domain in which this SEP resides. 2972 * 2973 * \param enc SES enclosure instance. 2974 */ 2975 static void 2976 ses_device_found(enc_softc_t *enc) 2977 { 2978 ses_poll_status(enc); 2979 enc_update_request(enc, SES_PUBLISH_PHYSPATHS); 2980 } 2981 2982 static struct enc_vec ses_enc_vec = 2983 { 2984 .softc_invalidate = ses_softc_invalidate, 2985 .softc_cleanup = ses_softc_cleanup, 2986 .init_enc = ses_init_enc, 2987 .set_enc_status = ses_set_enc_status, 2988 .get_elm_status = ses_get_elm_status, 2989 .set_elm_status = ses_set_elm_status, 2990 .get_elm_desc = ses_get_elm_desc, 2991 .get_elm_devnames = ses_get_elm_devnames, 2992 .handle_string = ses_handle_string, 2993 .device_found = ses_device_found, 2994 .poll_status = ses_poll_status 2995 }; 2996 2997 /** 2998 * \brief Initialize a new SES instance. 2999 * 3000 * \param enc SES softc structure to set up the instance in. 3001 * \param doinit Do the initialization (see main driver). 3002 * 3003 * \return 0 on success, errno otherwise. 3004 */ 3005 int 3006 ses_softc_init(enc_softc_t *enc) 3007 { 3008 ses_softc_t *ses_softc; 3009 3010 CAM_DEBUG(enc->periph->path, CAM_DEBUG_SUBTRACE, 3011 ("entering enc_softc_init(%p)\n", enc)); 3012 3013 enc->enc_vec = ses_enc_vec; 3014 enc->enc_fsm_states = enc_fsm_states; 3015 3016 if (enc->enc_private == NULL) 3017 enc->enc_private = ENC_MALLOCZ(sizeof(ses_softc_t)); 3018 if (enc->enc_cache.private == NULL) 3019 enc->enc_cache.private = ENC_MALLOCZ(sizeof(ses_cache_t)); 3020 if (enc->enc_daemon_cache.private == NULL) 3021 enc->enc_daemon_cache.private = 3022 ENC_MALLOCZ(sizeof(ses_cache_t)); 3023 3024 if (enc->enc_private == NULL 3025 || enc->enc_cache.private == NULL 3026 || enc->enc_daemon_cache.private == NULL) { 3027 ENC_FREE_AND_NULL(enc->enc_private); 3028 ENC_FREE_AND_NULL(enc->enc_cache.private); 3029 ENC_FREE_AND_NULL(enc->enc_daemon_cache.private); 3030 return (ENOMEM); 3031 } 3032 3033 ses_softc = enc->enc_private; 3034 TAILQ_INIT(&ses_softc->ses_requests); 3035 TAILQ_INIT(&ses_softc->ses_pending_requests); 3036 3037 enc_update_request(enc, SES_UPDATE_PAGES); 3038 3039 // XXX: Move this to the FSM so it doesn't hang init 3040 if (0) (void) ses_set_timed_completion(enc, 1); 3041 3042 return (0); 3043 } 3044