1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <scsi/libses.h> 30 #include "ses_impl.h" 31 32 ses_snap_page_t * 33 ses_snap_find_page(ses_snap_t *sp, ses2_diag_page_t page, boolean_t ctl) 34 { 35 ses_snap_page_t *pp; 36 37 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) 38 if (pp->ssp_num == page && pp->ssp_control == ctl && 39 (pp->ssp_len > 0 || pp->ssp_control)) 40 return (pp); 41 42 return (NULL); 43 } 44 45 static int 46 grow_snap_page(ses_snap_page_t *pp, size_t min) 47 { 48 uint8_t *newbuf; 49 50 if (min == 0 || min < pp->ssp_alloc) 51 min = pp->ssp_alloc * 2; 52 53 if ((newbuf = ses_realloc(pp->ssp_page, min)) == NULL) 54 return (-1); 55 56 pp->ssp_page = newbuf; 57 pp->ssp_alloc = min; 58 59 bzero(newbuf + pp->ssp_len, pp->ssp_alloc - pp->ssp_len); 60 61 return (0); 62 } 63 64 static ses_snap_page_t * 65 alloc_snap_page(void) 66 { 67 ses_snap_page_t *pp; 68 69 if ((pp = ses_zalloc(sizeof (ses_snap_page_t))) == NULL) 70 return (NULL); 71 72 if ((pp->ssp_page = ses_zalloc(SES2_MIN_DIAGPAGE_ALLOC)) == NULL) { 73 ses_free(pp); 74 return (NULL); 75 } 76 77 pp->ssp_num = -1; 78 pp->ssp_alloc = SES2_MIN_DIAGPAGE_ALLOC; 79 80 return (pp); 81 } 82 83 static void 84 free_snap_page(ses_snap_page_t *pp) 85 { 86 if (pp == NULL) 87 return; 88 89 if (pp->ssp_mmap_base) 90 (void) munmap(pp->ssp_mmap_base, pp->ssp_mmap_len); 91 else 92 ses_free(pp->ssp_page); 93 ses_free(pp); 94 } 95 96 static void 97 free_all_snap_pages(ses_snap_t *sp) 98 { 99 ses_snap_page_t *pp, *np; 100 101 for (pp = sp->ss_pages; pp != NULL; pp = np) { 102 np = pp->ssp_next; 103 free_snap_page(pp); 104 } 105 106 sp->ss_pages = NULL; 107 } 108 109 /* 110 * Grow (if needed) the control page buffer, fill in the page code, page 111 * length, and generation count, and return a pointer to the page. The 112 * caller is responsible for filling in the rest of the page data. If 'unique' 113 * is specified, then a new page instance is created instead of sharing the 114 * current one. 115 */ 116 ses_snap_page_t * 117 ses_snap_ctl_page(ses_snap_t *sp, ses2_diag_page_t page, size_t dlen, 118 boolean_t unique) 119 { 120 ses_target_t *tp = sp->ss_target; 121 spc3_diag_page_impl_t *pip; 122 ses_snap_page_t *pp, *up, **loc; 123 ses_pagedesc_t *dp; 124 size_t len; 125 126 pp = ses_snap_find_page(sp, page, B_TRUE); 127 if (pp == NULL) { 128 (void) ses_set_errno(ESES_NOTSUP); 129 return (NULL); 130 } 131 132 if (pp->ssp_initialized && !unique) 133 return (pp); 134 135 if (unique) { 136 /* 137 * The user has requested a unique instance of the page. Create 138 * a new ses_snap_page_t instance and chain it off the 139 * 'ssp_instances' list of the master page. These must be 140 * appended to the end of the chain, as the order of operations 141 * may be important (i.e. microcode download). 142 */ 143 if ((up = alloc_snap_page()) == NULL) 144 return (NULL); 145 146 up->ssp_num = pp->ssp_num; 147 up->ssp_control = B_TRUE; 148 149 for (loc = &pp->ssp_unique; *loc != NULL; 150 loc = &(*loc)->ssp_next) 151 ; 152 153 *loc = up; 154 pp = up; 155 } 156 157 dp = ses_get_pagedesc(tp, page, SES_PAGE_CTL); 158 ASSERT(dp != NULL); 159 160 len = dp->spd_ctl_len(sp->ss_n_elem, page, dlen); 161 if (pp->ssp_alloc < dlen && grow_snap_page(pp, len) != 0) 162 return (NULL); 163 pp->ssp_len = len; 164 bzero(pp->ssp_page, len); 165 pp->ssp_initialized = B_TRUE; 166 167 pip = (spc3_diag_page_impl_t *)pp->ssp_page; 168 pip->sdpi_page_code = (uint8_t)page; 169 SCSI_WRITE16(&pip->sdpi_page_length, 170 len - offsetof(spc3_diag_page_impl_t, sdpi_data[0])); 171 if (dp->spd_gcoff != -1) 172 SCSI_WRITE32((uint8_t *)pip + dp->spd_gcoff, sp->ss_generation); 173 174 return (pp); 175 } 176 177 static int 178 read_status_page(ses_snap_t *sp, ses2_diag_page_t page) 179 { 180 libscsi_action_t *ap; 181 ses_snap_page_t *pp; 182 ses_target_t *tp; 183 spc3_diag_page_impl_t *pip; 184 spc3_receive_diagnostic_results_cdb_t *cp; 185 uint_t flags; 186 uint8_t *buf; 187 size_t alloc; 188 uint_t retries = 0; 189 ses2_diag_page_t retpage; 190 191 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) 192 if (pp->ssp_num == page && !pp->ssp_control) 193 break; 194 195 /* 196 * No matching page. Since the page number is not under consumer or 197 * device control, this must be a bug. 198 */ 199 ASSERT(pp != NULL); 200 201 tp = sp->ss_target; 202 203 flags = LIBSCSI_AF_READ | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE | 204 LIBSCSI_AF_RQSENSE; 205 206 again: 207 ap = libscsi_action_alloc(tp->st_scsi_hdl, 208 SPC3_CMD_RECEIVE_DIAGNOSTIC_RESULTS, flags, pp->ssp_page, 209 pp->ssp_alloc); 210 211 if (ap == NULL) 212 return (ses_libscsi_error(tp->st_scsi_hdl, "failed to " 213 "allocate SCSI action")); 214 215 cp = (spc3_receive_diagnostic_results_cdb_t *) 216 libscsi_action_get_cdb(ap); 217 218 cp->rdrc_page_code = pp->ssp_num; 219 cp->rdrc_pcv = 1; 220 SCSI_WRITE16(&cp->rdrc_allocation_length, 221 MIN(pp->ssp_alloc, UINT16_MAX)); 222 223 if (libscsi_exec(ap, tp->st_target) != 0) { 224 libscsi_action_free(ap); 225 return (ses_libscsi_error(tp->st_scsi_hdl, 226 "receive diagnostic results failed")); 227 } 228 229 if (libscsi_action_get_status(ap) != 0) { 230 (void) ses_scsi_error(ap, 231 "receive diagnostic results failed"); 232 libscsi_action_free(ap); 233 return (-1); 234 } 235 236 (void) libscsi_action_get_buffer(ap, &buf, &alloc, &pp->ssp_len); 237 libscsi_action_free(ap); 238 239 ASSERT(buf == pp->ssp_page); 240 ASSERT(alloc == pp->ssp_alloc); 241 242 if (pp->ssp_len == pp->ssp_alloc && pp->ssp_alloc < UINT16_MAX) { 243 bzero(pp->ssp_page, pp->ssp_len); 244 pp->ssp_len = 0; 245 if (grow_snap_page(pp, 0) != 0) 246 return (-1); 247 goto again; 248 } 249 250 pip = (spc3_diag_page_impl_t *)buf; 251 252 if (pip->sdpi_page_code == page) 253 return (0); 254 255 retpage = pip->sdpi_page_code; 256 257 bzero(pp->ssp_page, pp->ssp_len); 258 pp->ssp_len = 0; 259 260 if (retpage == SES2_DIAGPAGE_ENCLOSURE_BUSY) { 261 if (++retries > LIBSES_MAX_BUSY_RETRIES) 262 return (ses_error(ESES_BUSY, "too many " 263 "enclosure busy responses for page 0x%x", page)); 264 goto again; 265 } 266 267 return (ses_error(ESES_BAD_RESPONSE, "target returned page 0x%x " 268 "instead of the requested page 0x%x", retpage, page)); 269 } 270 271 static int 272 send_control_page(ses_snap_t *sp, ses_snap_page_t *pp) 273 { 274 ses_target_t *tp; 275 libscsi_action_t *ap; 276 spc3_send_diagnostic_cdb_t *cp; 277 uint_t flags; 278 279 tp = sp->ss_target; 280 281 flags = LIBSCSI_AF_WRITE | LIBSCSI_AF_SILENT | LIBSCSI_AF_DIAGNOSE | 282 LIBSCSI_AF_RQSENSE; 283 284 ap = libscsi_action_alloc(tp->st_scsi_hdl, SPC3_CMD_SEND_DIAGNOSTIC, 285 flags, pp->ssp_page, pp->ssp_len); 286 287 if (ap == NULL) 288 return (ses_libscsi_error(tp->st_scsi_hdl, "failed to " 289 "allocate SCSI action")); 290 291 cp = (spc3_send_diagnostic_cdb_t *)libscsi_action_get_cdb(ap); 292 293 cp->sdc_pf = 1; 294 SCSI_WRITE16(&cp->sdc_parameter_list_length, pp->ssp_len); 295 296 if (libscsi_exec(ap, tp->st_target) != 0) { 297 libscsi_action_free(ap); 298 return (ses_libscsi_error(tp->st_scsi_hdl, 299 "SEND DIAGNOSTIC command failed for page 0x%x", 300 pp->ssp_num)); 301 } 302 303 if (libscsi_action_get_status(ap) != 0) { 304 (void) ses_scsi_error(ap, "SEND DIAGNOSTIC command " 305 "failed for page 0x%x", pp->ssp_num); 306 libscsi_action_free(ap); 307 return (-1); 308 } 309 310 libscsi_action_free(ap); 311 312 return (0); 313 } 314 315 static int 316 pages_skel_create(ses_snap_t *sp) 317 { 318 ses_snap_page_t *pp, *np; 319 ses_target_t *tp = sp->ss_target; 320 ses2_supported_ses_diag_page_impl_t *pip; 321 ses2_diag_page_t page; 322 size_t npages; 323 size_t pagelen; 324 off_t i; 325 326 ASSERT(sp->ss_pages == NULL); 327 328 if ((pp = alloc_snap_page()) == NULL) 329 return (-1); 330 331 pp->ssp_num = SES2_DIAGPAGE_SUPPORTED_PAGES; 332 pp->ssp_control = B_FALSE; 333 sp->ss_pages = pp; 334 335 if (read_status_page(sp, SES2_DIAGPAGE_SUPPORTED_PAGES) != 0) { 336 free_snap_page(pp); 337 sp->ss_pages = NULL; 338 return (-1); 339 } 340 341 pip = pp->ssp_page; 342 pagelen = pp->ssp_len; 343 344 npages = SCSI_READ16(&pip->sssdpi_page_length); 345 346 for (i = 0; i < npages; i++) { 347 if (!SES_WITHIN_PAGE(pip->sssdpi_pages + i, 1, pip, 348 pagelen)) 349 break; 350 351 page = (ses2_diag_page_t)pip->sssdpi_pages[i]; 352 /* 353 * Skip the page we already added during the bootstrap. 354 */ 355 if (page == SES2_DIAGPAGE_SUPPORTED_PAGES) 356 continue; 357 /* 358 * The end of the page list may be padded with zeros; ignore 359 * them all. 360 */ 361 if (page == 0 && i > 0) 362 break; 363 if ((np = alloc_snap_page()) == NULL) { 364 free_all_snap_pages(sp); 365 return (-1); 366 } 367 np->ssp_num = page; 368 pp->ssp_next = np; 369 pp = np; 370 371 /* 372 * Allocate a control page as well, if we can use it. 373 */ 374 if (ses_get_pagedesc(tp, page, SES_PAGE_CTL) != NULL) { 375 if ((np = alloc_snap_page()) == NULL) { 376 free_all_snap_pages(sp); 377 return (-1); 378 } 379 np->ssp_num = page; 380 np->ssp_control = B_TRUE; 381 pp->ssp_next = np; 382 pp = np; 383 } 384 } 385 386 return (0); 387 } 388 389 static void 390 ses_snap_free(ses_snap_t *sp) 391 { 392 free_all_snap_pages(sp); 393 ses_node_teardown(sp->ss_root); 394 ses_free(sp->ss_nodes); 395 ses_free(sp); 396 } 397 398 static void 399 ses_snap_rele_unlocked(ses_snap_t *sp) 400 { 401 ses_target_t *tp = sp->ss_target; 402 403 if (--sp->ss_refcnt != 0) 404 return; 405 406 if (sp->ss_next != NULL) 407 sp->ss_next->ss_prev = sp->ss_prev; 408 409 if (sp->ss_prev != NULL) 410 sp->ss_prev->ss_next = sp->ss_next; 411 else 412 tp->st_snapshots = sp->ss_next; 413 414 ses_snap_free(sp); 415 } 416 417 ses_snap_t * 418 ses_snap_hold(ses_target_t *tp) 419 { 420 ses_snap_t *sp; 421 422 (void) pthread_mutex_lock(&tp->st_lock); 423 sp = tp->st_snapshots; 424 sp->ss_refcnt++; 425 (void) pthread_mutex_unlock(&tp->st_lock); 426 427 return (sp); 428 } 429 430 void 431 ses_snap_rele(ses_snap_t *sp) 432 { 433 ses_target_t *tp = sp->ss_target; 434 435 (void) pthread_mutex_lock(&tp->st_lock); 436 ses_snap_rele_unlocked(sp); 437 (void) pthread_mutex_unlock(&tp->st_lock); 438 } 439 440 ses_snap_t * 441 ses_snap_new(ses_target_t *tp) 442 { 443 ses_snap_t *sp; 444 ses_snap_page_t *pp; 445 uint32_t gc; 446 uint_t retries = 0; 447 ses_pagedesc_t *dp; 448 size_t pages, pagesize, pagelen; 449 char *scratch; 450 451 if ((sp = ses_zalloc(sizeof (ses_snap_t))) == NULL) 452 return (NULL); 453 454 sp->ss_target = tp; 455 456 again: 457 free_all_snap_pages(sp); 458 459 if (pages_skel_create(sp) != 0) { 460 free(sp); 461 return (NULL); 462 } 463 464 sp->ss_generation = (uint32_t)-1; 465 sp->ss_time = gethrtime(); 466 467 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { 468 /* 469 * We skip all of: 470 * 471 * - Control pages 472 * - Pages we've already filled in 473 * - Pages we don't understand (those with no descriptor) 474 */ 475 if (pp->ssp_len > 0 || pp->ssp_control) 476 continue; 477 if ((dp = ses_get_pagedesc(tp, pp->ssp_num, 478 SES_PAGE_DIAG)) == NULL) 479 continue; 480 481 if (read_status_page(sp, pp->ssp_num) != 0) 482 continue; 483 484 /* 485 * If the generation code has changed, we don't have a valid 486 * snapshot. Start over. 487 */ 488 if (dp->spd_gcoff != -1 && 489 dp->spd_gcoff + 4 <= pp->ssp_len) { 490 gc = SCSI_READ32((uint8_t *)pp->ssp_page + 491 dp->spd_gcoff); 492 if (sp->ss_generation == (uint32_t)-1) { 493 sp->ss_generation = gc; 494 } else if (sp->ss_generation != gc) { 495 if (++retries > LIBSES_MAX_GC_RETRIES) { 496 (void) ses_error(ESES_TOOMUCHCHANGE, 497 "too many generation count " 498 "mismatches: page 0x%x gc %u " 499 "previous page %u", dp->spd_gcoff, 500 gc, sp->ss_generation); 501 ses_snap_free((ses_snap_t *)sp); 502 return (NULL); 503 } 504 goto again; 505 } 506 } 507 } 508 509 /* 510 * The LIBSES_TRUNCATE environment variable is a debugging tool which, 511 * if set, randomly truncates all pages (except 512 * SES2_DIAGPAGE_SUPPORTED_PAGES). In order to be truly evil, we 513 * mmap() each page with enough space after it so we can move the data 514 * up to the end of a page and unmap the following page so that any 515 * attempt to read past the end of the page results in a segfault. 516 */ 517 if (sp->ss_target->st_truncate) { 518 pagesize = PAGESIZE; 519 520 /* 521 * Count the maximum number of pages we will need and allocate 522 * the necessary space. 523 */ 524 pages = 0; 525 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { 526 if (pp->ssp_control || pp->ssp_len == 0) 527 continue; 528 529 pages += (P2ROUNDUP(pp->ssp_len, pagesize) / 530 pagesize) + 1; 531 } 532 533 if ((scratch = mmap(NULL, pages * pagesize, 534 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 535 -1, 0)) == MAP_FAILED) { 536 (void) ses_error(ESES_NOMEM, 537 "failed to mmap() pages for truncation"); 538 ses_snap_free(sp); 539 return (NULL); 540 } 541 542 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { 543 if (pp->ssp_control || pp->ssp_len == 0) 544 continue; 545 546 pages = P2ROUNDUP(pp->ssp_len, pagesize) / pagesize; 547 pp->ssp_mmap_base = scratch; 548 pp->ssp_mmap_len = pages * pagesize; 549 550 pagelen = lrand48() % pp->ssp_len; 551 (void) memcpy(pp->ssp_mmap_base + pp->ssp_mmap_len - 552 pagelen, pp->ssp_page, pagelen); 553 ses_free(pp->ssp_page); 554 pp->ssp_page = pp->ssp_mmap_base + pp->ssp_mmap_len - 555 pagelen; 556 pp->ssp_len = pagelen; 557 558 (void) munmap(pp->ssp_mmap_base + pages * pagesize, 559 pagesize); 560 scratch += (pages + 1) * pagesize; 561 } 562 } 563 564 565 if (ses_fill_snap(sp) != 0) { 566 ses_snap_free(sp); 567 return (NULL); 568 } 569 570 (void) pthread_mutex_lock(&tp->st_lock); 571 if (tp->st_snapshots != NULL) 572 ses_snap_rele_unlocked(tp->st_snapshots); 573 sp->ss_next = tp->st_snapshots; 574 if (tp->st_snapshots != NULL) 575 tp->st_snapshots->ss_prev = sp; 576 tp->st_snapshots = sp; 577 sp->ss_refcnt = 2; 578 (void) pthread_mutex_unlock(&tp->st_lock); 579 580 return (sp); 581 } 582 583 int 584 ses_snap_do_ctl(ses_snap_t *sp) 585 { 586 ses_snap_page_t *pp, *up; 587 int ret = -1; 588 589 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { 590 if (!pp->ssp_control) 591 continue; 592 593 if (pp->ssp_initialized && send_control_page(sp, pp) != 0) 594 goto error; 595 596 for (up = pp->ssp_unique; up != NULL; up = up->ssp_next) { 597 if (send_control_page(sp, up) != 0) 598 goto error; 599 } 600 } 601 602 ret = 0; 603 error: 604 for (pp = sp->ss_pages; pp != NULL; pp = pp->ssp_next) { 605 if (!pp->ssp_control) 606 continue; 607 608 pp->ssp_initialized = B_FALSE; 609 while ((up = pp->ssp_unique) != NULL) { 610 pp->ssp_unique = up->ssp_next; 611 free_snap_page(up); 612 } 613 } 614 615 616 return (ret); 617 } 618 619 uint32_t 620 ses_snap_generation(ses_snap_t *sp) 621 { 622 return (sp->ss_generation); 623 } 624 625 static ses_walk_action_t 626 ses_walk_node(ses_node_t *np, ses_walk_f func, void *arg) 627 { 628 ses_walk_action_t action; 629 630 for (; np != NULL; np = ses_node_sibling(np)) { 631 action = func(np, arg); 632 if (action == SES_WALK_ACTION_TERMINATE) 633 return (SES_WALK_ACTION_TERMINATE); 634 if (action == SES_WALK_ACTION_PRUNE || 635 ses_node_child(np) == NULL) 636 continue; 637 if (ses_walk_node(ses_node_child(np), func, arg) == 638 SES_WALK_ACTION_TERMINATE) 639 return (SES_WALK_ACTION_TERMINATE); 640 } 641 642 return (SES_WALK_ACTION_CONTINUE); 643 } 644 645 int 646 ses_walk(ses_snap_t *sp, ses_walk_f func, void *arg) 647 { 648 (void) ses_walk_node(ses_root_node(sp), func, arg); 649 650 return (0); 651 } 652 653 /*ARGSUSED*/ 654 static ses_walk_action_t 655 ses_fill_nodes(ses_node_t *np, void *unused) 656 { 657 np->sn_snapshot->ss_nodes[np->sn_id] = np; 658 659 return (SES_WALK_ACTION_CONTINUE); 660 } 661 662 /* 663 * Given an ID returned by ses_node_id(), lookup and return the corresponding 664 * node in the snapshot. If the snapshot generation count has changed, then 665 * return failure. 666 */ 667 ses_node_t * 668 ses_node_lookup(ses_snap_t *sp, uint64_t id) 669 { 670 uint32_t gen = (id >> 32); 671 uint32_t idx = (id & 0xFFFFFFFF); 672 673 if (sp->ss_generation != gen) { 674 (void) ses_set_errno(ESES_CHANGED); 675 return (NULL); 676 } 677 678 if (idx >= sp->ss_n_nodes) { 679 (void) ses_error(ESES_BAD_NODE, 680 "no such node in snapshot"); 681 return (NULL); 682 } 683 684 /* 685 * If this is our first lookup attempt, construct the array for fast 686 * lookups. 687 */ 688 if (sp->ss_nodes == NULL) { 689 if ((sp->ss_nodes = ses_zalloc( 690 sp->ss_n_nodes * sizeof (void *))) == NULL) 691 return (NULL); 692 693 (void) ses_walk(sp, ses_fill_nodes, NULL); 694 } 695 696 if (sp->ss_nodes[idx] == NULL) 697 (void) ses_error(ESES_BAD_NODE, 698 "no such node in snapshot"); 699 return (sp->ss_nodes[idx]); 700 } 701