1 /* $NetBSD: ses.c,v 1.50 2016/11/20 15:37:19 mlelstv Exp $ */ 2 /* 3 * Copyright (C) 2000 National Aeronautics & Space Administration 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. The name of the author may not be used to endorse or promote products 12 * derived from this software without specific prior written permission 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * Author: mjacob@nas.nasa.gov 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: ses.c,v 1.50 2016/11/20 15:37:19 mlelstv Exp $"); 30 31 #ifdef _KERNEL_OPT 32 #include "opt_scsi.h" 33 #endif 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/file.h> 39 #include <sys/stat.h> 40 #include <sys/ioctl.h> 41 #include <sys/scsiio.h> 42 #include <sys/buf.h> 43 #include <sys/uio.h> 44 #include <sys/malloc.h> 45 #include <sys/errno.h> 46 #include <sys/device.h> 47 #include <sys/disklabel.h> 48 #include <sys/disk.h> 49 #include <sys/proc.h> 50 #include <sys/conf.h> 51 #include <sys/vnode.h> 52 53 #include <dev/scsipi/scsipi_all.h> 54 #include <dev/scsipi/scsipi_disk.h> 55 #include <dev/scsipi/scsi_all.h> 56 #include <dev/scsipi/scsi_disk.h> 57 #include <dev/scsipi/scsipiconf.h> 58 #include <dev/scsipi/scsipi_base.h> 59 #include <dev/scsipi/ses.h> 60 61 /* 62 * Platform Independent Driver Internal Definitions for SES devices. 63 */ 64 typedef enum { 65 SES_NONE, 66 SES_SES_SCSI2, 67 SES_SES, 68 SES_SES_PASSTHROUGH, 69 SES_SEN, 70 SES_SAFT 71 } enctyp; 72 73 struct ses_softc; 74 typedef struct ses_softc ses_softc_t; 75 typedef struct { 76 int (*softc_init)(ses_softc_t *, int); 77 int (*init_enc)(ses_softc_t *); 78 int (*get_encstat)(ses_softc_t *, int); 79 int (*set_encstat)(ses_softc_t *, ses_encstat, int); 80 int (*get_objstat)(ses_softc_t *, ses_objstat *, int); 81 int (*set_objstat)(ses_softc_t *, ses_objstat *, int); 82 } encvec; 83 84 #define ENCI_SVALID 0x80 85 86 typedef struct { 87 uint32_t 88 enctype : 8, /* enclosure type */ 89 subenclosure : 8, /* subenclosure id */ 90 svalid : 1, /* enclosure information valid */ 91 priv : 15; /* private data, per object */ 92 uint8_t encstat[4]; /* state && stats */ 93 } encobj; 94 95 #define SEN_ID "UNISYS SUN_SEN" 96 #define SEN_ID_LEN 24 97 98 static enctyp ses_type(struct scsipi_inquiry_data *); 99 100 101 /* Forward reference to Enclosure Functions */ 102 static int ses_softc_init(ses_softc_t *, int); 103 static int ses_init_enc(ses_softc_t *); 104 static int ses_get_encstat(ses_softc_t *, int); 105 static int ses_set_encstat(ses_softc_t *, uint8_t, int); 106 static int ses_get_objstat(ses_softc_t *, ses_objstat *, int); 107 static int ses_set_objstat(ses_softc_t *, ses_objstat *, int); 108 109 static int safte_softc_init(ses_softc_t *, int); 110 static int safte_init_enc(ses_softc_t *); 111 static int safte_get_encstat(ses_softc_t *, int); 112 static int safte_set_encstat(ses_softc_t *, uint8_t, int); 113 static int safte_get_objstat(ses_softc_t *, ses_objstat *, int); 114 static int safte_set_objstat(ses_softc_t *, ses_objstat *, int); 115 116 /* 117 * Platform implementation defines/functions for SES internal kernel stuff 118 */ 119 120 #define STRNCMP strncmp 121 #define PRINTF printf 122 #define SES_LOG ses_log 123 #if defined(DEBUG) || defined(SCSIDEBUG) 124 #define SES_VLOG ses_log 125 #else 126 #define SES_VLOG if (0) ses_log 127 #endif 128 #define SES_MALLOC(amt) malloc(amt, M_DEVBUF, M_NOWAIT) 129 #define SES_FREE(ptr, amt) free(ptr, M_DEVBUF) 130 #define MEMZERO(dest, amt) memset(dest, 0, amt) 131 #define MEMCPY(dest, src, amt) memcpy(dest, src, amt) 132 #define RECEIVE_DIAGNOSTIC 0x1c 133 #define SEND_DIAGNOSTIC 0x1d 134 #define WRITE_BUFFER 0x3b 135 #define READ_BUFFER 0x3c 136 137 static dev_type_open(sesopen); 138 static dev_type_close(sesclose); 139 static dev_type_ioctl(sesioctl); 140 141 const struct cdevsw ses_cdevsw = { 142 .d_open = sesopen, 143 .d_close = sesclose, 144 .d_read = noread, 145 .d_write = nowrite, 146 .d_ioctl = sesioctl, 147 .d_stop = nostop, 148 .d_tty = notty, 149 .d_poll = nopoll, 150 .d_mmap = nommap, 151 .d_kqfilter = nokqfilter, 152 .d_discard = nodiscard, 153 .d_flag = D_OTHER | D_MPSAFE 154 }; 155 156 static int ses_runcmd(struct ses_softc *, char *, int, char *, int *); 157 static void ses_log(struct ses_softc *, const char *, ...) 158 __attribute__((__format__(__printf__, 2, 3))); 159 160 /* 161 * General NetBSD kernel stuff. 162 */ 163 164 struct ses_softc { 165 device_t sc_dev; 166 struct scsipi_periph *sc_periph; 167 enctyp ses_type; /* type of enclosure */ 168 encvec ses_vec; /* vector to handlers */ 169 void * ses_private; /* per-type private data */ 170 encobj * ses_objmap; /* objects */ 171 u_int32_t ses_nobjects; /* number of objects */ 172 ses_encstat ses_encstat; /* overall status */ 173 u_int8_t ses_flags; 174 }; 175 #define SES_FLAG_INVALID 0x01 176 #define SES_FLAG_OPEN 0x02 177 #define SES_FLAG_INITIALIZED 0x04 178 179 #define SESUNIT(x) (minor((x))) 180 181 static int ses_match(device_t, cfdata_t, void *); 182 static void ses_attach(device_t, device_t, void *); 183 static int ses_detach(device_t, int); 184 static enctyp ses_device_type(struct scsipibus_attach_args *); 185 186 CFATTACH_DECL_NEW(ses, sizeof (struct ses_softc), 187 ses_match, ses_attach, ses_detach, NULL); 188 189 extern struct cfdriver ses_cd; 190 191 static const struct scsipi_periphsw ses_switch = { 192 NULL, 193 NULL, 194 NULL, 195 NULL 196 }; 197 198 static int 199 ses_match(device_t parent, cfdata_t match, void *aux) 200 { 201 struct scsipibus_attach_args *sa = aux; 202 203 switch (ses_device_type(sa)) { 204 case SES_SES: 205 case SES_SES_SCSI2: 206 case SES_SEN: 207 case SES_SAFT: 208 case SES_SES_PASSTHROUGH: 209 /* 210 * For these devices, it's a perfect match. 211 */ 212 return (24); 213 default: 214 return (0); 215 } 216 } 217 218 219 /* 220 * Complete the attachment. 221 * 222 * We have to repeat the rerun of INQUIRY data as above because 223 * it's not until the return from the match routine that we have 224 * the softc available to set stuff in. 225 */ 226 static void 227 ses_attach(device_t parent, device_t self, void *aux) 228 { 229 const char *tname; 230 struct ses_softc *softc = device_private(self); 231 struct scsipibus_attach_args *sa = aux; 232 struct scsipi_periph *periph = sa->sa_periph; 233 234 softc->sc_dev = self; 235 SC_DEBUG(periph, SCSIPI_DB2, ("ssattach: ")); 236 softc->sc_periph = periph; 237 periph->periph_dev = self; 238 periph->periph_switch = &ses_switch; 239 periph->periph_openings = 1; 240 241 softc->ses_type = ses_device_type(sa); 242 switch (softc->ses_type) { 243 case SES_SES: 244 case SES_SES_SCSI2: 245 case SES_SES_PASSTHROUGH: 246 softc->ses_vec.softc_init = ses_softc_init; 247 softc->ses_vec.init_enc = ses_init_enc; 248 softc->ses_vec.get_encstat = ses_get_encstat; 249 softc->ses_vec.set_encstat = ses_set_encstat; 250 softc->ses_vec.get_objstat = ses_get_objstat; 251 softc->ses_vec.set_objstat = ses_set_objstat; 252 break; 253 case SES_SAFT: 254 softc->ses_vec.softc_init = safte_softc_init; 255 softc->ses_vec.init_enc = safte_init_enc; 256 softc->ses_vec.get_encstat = safte_get_encstat; 257 softc->ses_vec.set_encstat = safte_set_encstat; 258 softc->ses_vec.get_objstat = safte_get_objstat; 259 softc->ses_vec.set_objstat = safte_set_objstat; 260 break; 261 case SES_SEN: 262 break; 263 case SES_NONE: 264 default: 265 break; 266 } 267 268 switch (softc->ses_type) { 269 default: 270 case SES_NONE: 271 tname = "No SES device"; 272 break; 273 case SES_SES_SCSI2: 274 tname = "SCSI-2 SES Device"; 275 break; 276 case SES_SES: 277 tname = "SCSI-3 SES Device"; 278 break; 279 case SES_SES_PASSTHROUGH: 280 tname = "SES Passthrough Device"; 281 break; 282 case SES_SEN: 283 tname = "UNISYS SEN Device (NOT HANDLED YET)"; 284 break; 285 case SES_SAFT: 286 tname = "SAF-TE Compliant Device"; 287 break; 288 } 289 aprint_naive("\n"); 290 aprint_normal("\n%s: %s\n", device_xname(softc->sc_dev), tname); 291 } 292 293 static enctyp 294 ses_device_type(struct scsipibus_attach_args *sa) 295 { 296 struct scsipi_inquiry_data *inqp = sa->sa_inqptr; 297 298 if (inqp == NULL) 299 return (SES_NONE); 300 301 return (ses_type(inqp)); 302 } 303 304 static int 305 sesopen(dev_t dev, int flags, int fmt, struct lwp *l) 306 { 307 struct ses_softc *softc; 308 int error, unit; 309 310 unit = SESUNIT(dev); 311 softc = device_lookup_private(&ses_cd, unit); 312 if (softc == NULL) 313 return (ENXIO); 314 315 if (softc->ses_flags & SES_FLAG_INVALID) { 316 error = ENXIO; 317 goto out; 318 } 319 if (softc->ses_flags & SES_FLAG_OPEN) { 320 error = EBUSY; 321 goto out; 322 } 323 if (softc->ses_vec.softc_init == NULL) { 324 error = ENXIO; 325 goto out; 326 } 327 error = scsipi_adapter_addref( 328 softc->sc_periph->periph_channel->chan_adapter); 329 if (error != 0) 330 goto out; 331 332 333 softc->ses_flags |= SES_FLAG_OPEN; 334 if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) { 335 error = (*softc->ses_vec.softc_init)(softc, 1); 336 if (error) 337 softc->ses_flags &= ~SES_FLAG_OPEN; 338 else 339 softc->ses_flags |= SES_FLAG_INITIALIZED; 340 } 341 342 out: 343 return (error); 344 } 345 346 static int 347 sesclose(dev_t dev, int flags, int fmt, 348 struct lwp *l) 349 { 350 struct ses_softc *softc; 351 int unit; 352 353 unit = SESUNIT(dev); 354 softc = device_lookup_private(&ses_cd, unit); 355 if (softc == NULL) 356 return (ENXIO); 357 358 scsipi_wait_drain(softc->sc_periph); 359 scsipi_adapter_delref(softc->sc_periph->periph_channel->chan_adapter); 360 softc->ses_flags &= ~SES_FLAG_OPEN; 361 return (0); 362 } 363 364 static int 365 sesioctl(dev_t dev, u_long cmd, void *arg_addr, int flag, struct lwp *l) 366 { 367 ses_encstat tmp; 368 ses_objstat objs; 369 ses_object obj, *uobj; 370 struct ses_softc *ssc = device_lookup_private(&ses_cd, SESUNIT(dev)); 371 void *addr; 372 int error, i; 373 374 375 if (arg_addr) 376 addr = *((void **) arg_addr); 377 else 378 addr = NULL; 379 380 SC_DEBUG(ssc->sc_periph, SCSIPI_DB2, ("sesioctl 0x%lx ", cmd)); 381 382 /* 383 * Now check to see whether we're initialized or not. 384 */ 385 if ((ssc->ses_flags & SES_FLAG_INITIALIZED) == 0) { 386 return (ENODEV); 387 } 388 389 error = 0; 390 391 /* 392 * If this command can change the device's state, 393 * we must have the device open for writing. 394 */ 395 switch (cmd) { 396 case SESIOC_GETNOBJ: 397 case SESIOC_GETOBJMAP: 398 case SESIOC_GETENCSTAT: 399 case SESIOC_GETOBJSTAT: 400 break; 401 default: 402 if ((flag & FWRITE) == 0) { 403 return (EBADF); 404 } 405 } 406 407 switch (cmd) { 408 case SESIOC_GETNOBJ: 409 if (addr == NULL) 410 return EINVAL; 411 error = copyout(&ssc->ses_nobjects, addr, 412 sizeof (ssc->ses_nobjects)); 413 break; 414 415 case SESIOC_GETOBJMAP: 416 if (addr == NULL) 417 return EINVAL; 418 for (uobj = addr, i = 0; i != ssc->ses_nobjects; i++, uobj++) { 419 obj.obj_id = i; 420 obj.subencid = ssc->ses_objmap[i].subenclosure; 421 obj.object_type = ssc->ses_objmap[i].enctype; 422 error = copyout(&obj, uobj, sizeof (ses_object)); 423 if (error) { 424 break; 425 } 426 } 427 break; 428 429 case SESIOC_GETENCSTAT: 430 if (addr == NULL) 431 return EINVAL; 432 error = (*ssc->ses_vec.get_encstat)(ssc, 1); 433 if (error) 434 break; 435 tmp = ssc->ses_encstat & ~ENCI_SVALID; 436 error = copyout(&tmp, addr, sizeof (ses_encstat)); 437 ssc->ses_encstat = tmp; 438 break; 439 440 case SESIOC_SETENCSTAT: 441 if (addr == NULL) 442 return EINVAL; 443 error = copyin(addr, &tmp, sizeof (ses_encstat)); 444 if (error) 445 break; 446 error = (*ssc->ses_vec.set_encstat)(ssc, tmp, 1); 447 break; 448 449 case SESIOC_GETOBJSTAT: 450 if (addr == NULL) 451 return EINVAL; 452 error = copyin(addr, &objs, sizeof (ses_objstat)); 453 if (error) 454 break; 455 if (objs.obj_id >= ssc->ses_nobjects) { 456 error = EINVAL; 457 break; 458 } 459 error = (*ssc->ses_vec.get_objstat)(ssc, &objs, 1); 460 if (error) 461 break; 462 error = copyout(&objs, addr, sizeof (ses_objstat)); 463 /* 464 * Always (for now) invalidate entry. 465 */ 466 ssc->ses_objmap[objs.obj_id].svalid = 0; 467 break; 468 469 case SESIOC_SETOBJSTAT: 470 if (addr == NULL) 471 return EINVAL; 472 error = copyin(addr, &objs, sizeof (ses_objstat)); 473 if (error) 474 break; 475 476 if (objs.obj_id >= ssc->ses_nobjects) { 477 error = EINVAL; 478 break; 479 } 480 error = (*ssc->ses_vec.set_objstat)(ssc, &objs, 1); 481 482 /* 483 * Always (for now) invalidate entry. 484 */ 485 ssc->ses_objmap[objs.obj_id].svalid = 0; 486 break; 487 488 case SESIOC_INIT: 489 490 error = (*ssc->ses_vec.init_enc)(ssc); 491 break; 492 493 default: 494 error = scsipi_do_ioctl(ssc->sc_periph, 495 dev, cmd, arg_addr, flag, l); 496 break; 497 } 498 return (error); 499 } 500 501 static int 502 ses_runcmd(struct ses_softc *ssc, char *cdb, int cdbl, char *dptr, int *dlenp) 503 { 504 struct scsipi_generic sgen; 505 int dl, flg, error; 506 507 if (dptr) { 508 if ((dl = *dlenp) < 0) { 509 dl = -dl; 510 flg = XS_CTL_DATA_OUT; 511 } else { 512 flg = XS_CTL_DATA_IN; 513 } 514 } else { 515 dl = 0; 516 flg = 0; 517 } 518 519 if (cdbl > sizeof (struct scsipi_generic)) { 520 cdbl = sizeof (struct scsipi_generic); 521 } 522 memcpy(&sgen, cdb, cdbl); 523 #ifndef SCSIDEBUG 524 flg |= XS_CTL_SILENT; 525 #endif 526 error = scsipi_command(ssc->sc_periph, &sgen, cdbl, 527 (u_char *) dptr, dl, SCSIPIRETRIES, 30000, NULL, flg); 528 529 if (error == 0 && dptr) 530 *dlenp = 0; 531 532 return (error); 533 } 534 535 static void 536 ses_log(struct ses_softc *ssc, const char *fmt, ...) 537 { 538 va_list ap; 539 540 printf("%s: ", device_xname(ssc->sc_dev)); 541 va_start(ap, fmt); 542 vprintf(fmt, ap); 543 va_end(ap); 544 } 545 546 /* 547 * The code after this point runs on many platforms, 548 * so forgive the slightly awkward and nonconforming 549 * appearance. 550 */ 551 552 /* 553 * Is this a device that supports enclosure services? 554 * 555 * It's a a pretty simple ruleset- if it is device type 0x0D (13), it's 556 * an SES device. If it happens to be an old UNISYS SEN device, we can 557 * handle that too. 558 */ 559 560 #define SAFTE_START 44 561 #define SAFTE_END 50 562 #define SAFTE_LEN SAFTE_END-SAFTE_START 563 564 static enctyp 565 ses_type(struct scsipi_inquiry_data *inqp) 566 { 567 size_t given_len = inqp->additional_length + 4; 568 569 if (given_len < 8+SEN_ID_LEN) 570 return (SES_NONE); 571 572 if ((inqp->device & SID_TYPE) == T_ENCLOSURE) { 573 if (STRNCMP(inqp->vendor, SEN_ID, SEN_ID_LEN) == 0) { 574 return (SES_SEN); 575 } else if ((inqp->version & SID_ANSII) > 2) { 576 return (SES_SES); 577 } else { 578 return (SES_SES_SCSI2); 579 } 580 return (SES_NONE); 581 } 582 583 #ifdef SES_ENABLE_PASSTHROUGH 584 if ((inqp->flags2 & SID_EncServ) && (inqp->version & SID_ANSII) >= 2) { 585 /* 586 * PassThrough Device. 587 */ 588 return (SES_SES_PASSTHROUGH); 589 } 590 #endif 591 592 /* 593 * The comparison is short for a reason- 594 * some vendors were chopping it short. 595 */ 596 597 if (given_len < SAFTE_END - 2) { 598 return (SES_NONE); 599 } 600 601 if (STRNCMP((char *)&inqp->vendor_specific[8], "SAF-TE", 602 SAFTE_LEN - 2) == 0) { 603 return (SES_SAFT); 604 } 605 606 return (SES_NONE); 607 } 608 609 /* 610 * SES Native Type Device Support 611 */ 612 613 /* 614 * SES Diagnostic Page Codes 615 */ 616 617 typedef enum { 618 SesConfigPage = 0x1, 619 SesControlPage, 620 #define SesStatusPage SesControlPage 621 SesHelpTxt, 622 SesStringOut, 623 #define SesStringIn SesStringOut 624 SesThresholdOut, 625 #define SesThresholdIn SesThresholdOut 626 SesArrayControl, 627 #define SesArrayStatus SesArrayControl 628 SesElementDescriptor, 629 SesShortStatus 630 } SesDiagPageCodes; 631 632 /* 633 * minimal amounts 634 */ 635 636 /* 637 * Minimum amount of data, starting from byte 0, to have 638 * the config header. 639 */ 640 #define SES_CFGHDR_MINLEN 12 641 642 /* 643 * Minimum amount of data, starting from byte 0, to have 644 * the config header and one enclosure header. 645 */ 646 #define SES_ENCHDR_MINLEN 48 647 648 /* 649 * Take this value, subtract it from VEnclen and you know 650 * the length of the vendor unique bytes. 651 */ 652 #define SES_ENCHDR_VMIN 36 653 654 /* 655 * SES Data Structures 656 */ 657 658 typedef struct { 659 uint32_t GenCode; /* Generation Code */ 660 uint8_t Nsubenc; /* Number of Subenclosures */ 661 } SesCfgHdr; 662 663 typedef struct { 664 uint8_t Subencid; /* SubEnclosure Identifier */ 665 uint8_t Ntypes; /* # of supported types */ 666 uint8_t VEnclen; /* Enclosure Descriptor Length */ 667 } SesEncHdr; 668 669 typedef struct { 670 uint8_t encWWN[8]; /* XXX- Not Right Yet */ 671 uint8_t encVid[8]; 672 uint8_t encPid[16]; 673 uint8_t encRev[4]; 674 uint8_t encVen[1]; 675 } SesEncDesc; 676 677 typedef struct { 678 uint8_t enc_type; /* type of element */ 679 uint8_t enc_maxelt; /* maximum supported */ 680 uint8_t enc_subenc; /* in SubEnc # N */ 681 uint8_t enc_tlen; /* Type Descriptor Text Length */ 682 } SesThdr; 683 684 typedef struct { 685 uint8_t comstatus; 686 uint8_t comstat[3]; 687 } SesComStat; 688 689 struct typidx { 690 int ses_tidx; 691 int ses_oidx; 692 }; 693 694 struct sscfg { 695 uint8_t ses_ntypes; /* total number of types supported */ 696 697 /* 698 * We need to keep a type index as well as an 699 * object index for each object in an enclosure. 700 */ 701 struct typidx *ses_typidx; 702 703 /* 704 * We also need to keep track of the number of elements 705 * per type of element. This is needed later so that we 706 * can find precisely in the returned status data the 707 * status for the Nth element of the Kth type. 708 */ 709 uint8_t * ses_eltmap; 710 }; 711 712 713 /* 714 * (de)canonicalization defines 715 */ 716 #define sbyte(x, byte) ((((uint32_t)(x)) >> (byte * 8)) & 0xff) 717 #define sbit(x, bit) (((uint32_t)(x)) << bit) 718 #define sset8(outp, idx, sval) (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0) 719 720 #define sset16(outp, idx, sval) \ 721 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \ 722 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0) 723 724 725 #define sset24(outp, idx, sval) \ 726 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \ 727 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \ 728 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0) 729 730 731 #define sset32(outp, idx, sval) \ 732 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 3), \ 733 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 2), \ 734 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 1), \ 735 (((uint8_t *)(outp))[idx++]) = sbyte(sval, 0) 736 737 #define gbyte(x, byte) ((((uint32_t)(x)) & 0xff) << (byte * 8)) 738 #define gbit(lv, in, idx, shft, mask) lv = ((in[idx] >> shft) & mask) 739 #define sget8(inp, idx, lval) lval = (((uint8_t *)(inp))[idx++]) 740 #define gget8(inp, idx, lval) lval = (((uint8_t *)(inp))[idx]) 741 742 #define sget16(inp, idx, lval) \ 743 lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \ 744 (((uint8_t *)(inp))[idx+1]), idx += 2 745 746 #define gget16(inp, idx, lval) \ 747 lval = gbyte((((uint8_t *)(inp))[idx]), 1) | \ 748 (((uint8_t *)(inp))[idx+1]) 749 750 #define sget24(inp, idx, lval) \ 751 lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \ 752 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \ 753 (((uint8_t *)(inp))[idx+2]), idx += 3 754 755 #define gget24(inp, idx, lval) \ 756 lval = gbyte((((uint8_t *)(inp))[idx]), 2) | \ 757 gbyte((((uint8_t *)(inp))[idx+1]), 1) | \ 758 (((uint8_t *)(inp))[idx+2]) 759 760 #define sget32(inp, idx, lval) \ 761 lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \ 762 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \ 763 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \ 764 (((uint8_t *)(inp))[idx+3]), idx += 4 765 766 #define gget32(inp, idx, lval) \ 767 lval = gbyte((((uint8_t *)(inp))[idx]), 3) | \ 768 gbyte((((uint8_t *)(inp))[idx+1]), 2) | \ 769 gbyte((((uint8_t *)(inp))[idx+2]), 1) | \ 770 (((uint8_t *)(inp))[idx+3]) 771 772 #define SCSZ 0x2000 773 #define CFLEN (256 + SES_ENCHDR_MINLEN) 774 775 /* 776 * Routines specific && private to SES only 777 */ 778 779 static int ses_getconfig(ses_softc_t *); 780 static int ses_getputstat(ses_softc_t *, int, SesComStat *, int, int); 781 static int ses_cfghdr(uint8_t *, int, SesCfgHdr *); 782 static int ses_enchdr(uint8_t *, int, uint8_t, SesEncHdr *); 783 static int ses_encdesc(uint8_t *, int, uint8_t, SesEncDesc *); 784 static int ses_getthdr(uint8_t *, int, int, SesThdr *); 785 static int ses_decode(char *, int, uint8_t *, int, int, SesComStat *); 786 static int ses_encode(char *, int, uint8_t *, int, int, SesComStat *); 787 788 static int 789 ses_softc_init(ses_softc_t *ssc, int doinit) 790 { 791 if (doinit == 0) { 792 struct sscfg *cc; 793 if (ssc->ses_nobjects) { 794 SES_FREE(ssc->ses_objmap, 795 ssc->ses_nobjects * sizeof (encobj)); 796 ssc->ses_objmap = NULL; 797 } 798 if ((cc = ssc->ses_private) != NULL) { 799 if (cc->ses_eltmap && cc->ses_ntypes) { 800 SES_FREE(cc->ses_eltmap, cc->ses_ntypes); 801 cc->ses_eltmap = NULL; 802 cc->ses_ntypes = 0; 803 } 804 if (cc->ses_typidx && ssc->ses_nobjects) { 805 SES_FREE(cc->ses_typidx, 806 ssc->ses_nobjects * sizeof (struct typidx)); 807 cc->ses_typidx = NULL; 808 } 809 SES_FREE(cc, sizeof (struct sscfg)); 810 ssc->ses_private = NULL; 811 } 812 ssc->ses_nobjects = 0; 813 return (0); 814 } 815 if (ssc->ses_private == NULL) { 816 ssc->ses_private = SES_MALLOC(sizeof (struct sscfg)); 817 } 818 if (ssc->ses_private == NULL) { 819 return (ENOMEM); 820 } 821 ssc->ses_nobjects = 0; 822 ssc->ses_encstat = 0; 823 return (ses_getconfig(ssc)); 824 } 825 826 static int 827 ses_detach(device_t self, int flags) 828 { 829 struct ses_softc *ssc = device_private(self); 830 struct sscfg *cc = ssc->ses_private; 831 832 if (ssc->ses_objmap) { 833 SES_FREE(ssc->ses_objmap, (nobj * sizeof (encobj))); 834 } 835 if (cc != NULL) { 836 if (cc->ses_typidx) { 837 SES_FREE(cc->ses_typidx, 838 (nobj * sizeof (struct typidx))); 839 } 840 if (cc->ses_eltmap) { 841 SES_FREE(cc->ses_eltmap, ntype); 842 } 843 SES_FREE(cc, sizeof (struct sscfg)); 844 } 845 846 return 0; 847 } 848 849 static int 850 ses_init_enc(ses_softc_t *ssc) 851 { 852 return (0); 853 } 854 855 static int 856 ses_get_encstat(ses_softc_t *ssc, int slpflag) 857 { 858 SesComStat ComStat; 859 int status; 860 861 if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 1)) != 0) { 862 return (status); 863 } 864 ssc->ses_encstat = ComStat.comstatus | ENCI_SVALID; 865 return (0); 866 } 867 868 static int 869 ses_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflag) 870 { 871 SesComStat ComStat; 872 int status; 873 874 ComStat.comstatus = encstat & 0xf; 875 if ((status = ses_getputstat(ssc, -1, &ComStat, slpflag, 0)) != 0) { 876 return (status); 877 } 878 ssc->ses_encstat = encstat & 0xf; /* note no SVALID set */ 879 return (0); 880 } 881 882 static int 883 ses_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag) 884 { 885 int i = (int)obp->obj_id; 886 887 if (ssc->ses_objmap[i].svalid == 0) { 888 SesComStat ComStat; 889 int err = ses_getputstat(ssc, i, &ComStat, slpflag, 1); 890 if (err) 891 return (err); 892 ssc->ses_objmap[i].encstat[0] = ComStat.comstatus; 893 ssc->ses_objmap[i].encstat[1] = ComStat.comstat[0]; 894 ssc->ses_objmap[i].encstat[2] = ComStat.comstat[1]; 895 ssc->ses_objmap[i].encstat[3] = ComStat.comstat[2]; 896 ssc->ses_objmap[i].svalid = 1; 897 } 898 obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; 899 obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; 900 obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; 901 obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; 902 return (0); 903 } 904 905 static int 906 ses_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflag) 907 { 908 SesComStat ComStat; 909 int err; 910 /* 911 * If this is clear, we don't do diddly. 912 */ 913 if ((obp->cstat[0] & SESCTL_CSEL) == 0) { 914 return (0); 915 } 916 ComStat.comstatus = obp->cstat[0]; 917 ComStat.comstat[0] = obp->cstat[1]; 918 ComStat.comstat[1] = obp->cstat[2]; 919 ComStat.comstat[2] = obp->cstat[3]; 920 err = ses_getputstat(ssc, (int)obp->obj_id, &ComStat, slpflag, 0); 921 ssc->ses_objmap[(int)obp->obj_id].svalid = 0; 922 return (err); 923 } 924 925 static int 926 ses_getconfig(ses_softc_t *ssc) 927 { 928 struct sscfg *cc; 929 SesCfgHdr cf; 930 SesEncHdr hd; 931 SesEncDesc *cdp; 932 SesThdr thdr; 933 int err, amt, i, nobj, ntype, maxima; 934 char storage[CFLEN], *sdata; 935 static char cdb[6] = { 936 RECEIVE_DIAGNOSTIC, 0x1, SesConfigPage, SCSZ >> 8, SCSZ & 0xff, 0 937 }; 938 939 cc = ssc->ses_private; 940 if (cc == NULL) { 941 return (ENXIO); 942 } 943 944 sdata = SES_MALLOC(SCSZ); 945 if (sdata == NULL) 946 return (ENOMEM); 947 948 amt = SCSZ; 949 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 950 if (err) { 951 SES_FREE(sdata, SCSZ); 952 return (err); 953 } 954 amt = SCSZ - amt; 955 956 if (ses_cfghdr((uint8_t *) sdata, amt, &cf)) { 957 SES_LOG(ssc, "Unable to parse SES Config Header\n"); 958 SES_FREE(sdata, SCSZ); 959 return (EIO); 960 } 961 if (amt < SES_ENCHDR_MINLEN) { 962 SES_LOG(ssc, "runt enclosure length (%d)\n", amt); 963 SES_FREE(sdata, SCSZ); 964 return (EIO); 965 } 966 967 SES_VLOG(ssc, "GenCode %x %d Subenclosures\n", cf.GenCode, cf.Nsubenc); 968 969 /* 970 * Now waltz through all the subenclosures toting up the 971 * number of types available in each. For this, we only 972 * really need the enclosure header. However, we get the 973 * enclosure descriptor for debug purposes, as well 974 * as self-consistency checking purposes. 975 */ 976 977 maxima = cf.Nsubenc + 1; 978 cdp = (SesEncDesc *) storage; 979 for (ntype = i = 0; i < maxima; i++) { 980 MEMZERO((void *)cdp, sizeof (*cdp)); 981 if (ses_enchdr((uint8_t *) sdata, amt, i, &hd)) { 982 SES_LOG(ssc, "Cannot Extract Enclosure Header %d\n", i); 983 SES_FREE(sdata, SCSZ); 984 return (EIO); 985 } 986 SES_VLOG(ssc, " SubEnclosure ID %d, %d Types With this ID, En" 987 "closure Length %d\n", hd.Subencid, hd.Ntypes, hd.VEnclen); 988 989 if (ses_encdesc((uint8_t *)sdata, amt, i, cdp)) { 990 SES_LOG(ssc, "Can't get Enclosure Descriptor %d\n", i); 991 SES_FREE(sdata, SCSZ); 992 return (EIO); 993 } 994 SES_VLOG(ssc, " WWN: %02x%02x%02x%02x%02x%02x%02x%02x\n", 995 cdp->encWWN[0], cdp->encWWN[1], cdp->encWWN[2], 996 cdp->encWWN[3], cdp->encWWN[4], cdp->encWWN[5], 997 cdp->encWWN[6], cdp->encWWN[7]); 998 ntype += hd.Ntypes; 999 } 1000 1001 /* 1002 * Now waltz through all the types that are available, getting 1003 * the type header so we can start adding up the number of 1004 * objects available. 1005 */ 1006 for (nobj = i = 0; i < ntype; i++) { 1007 if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) { 1008 SES_LOG(ssc, "Can't get Enclosure Type Header %d\n", i); 1009 SES_FREE(sdata, SCSZ); 1010 return (EIO); 1011 } 1012 SES_LOG(ssc, " Type Desc[%d]: Type 0x%x, MaxElt %d, In Subenc " 1013 "%d, Text Length %d\n", i, thdr.enc_type, thdr.enc_maxelt, 1014 thdr.enc_subenc, thdr.enc_tlen); 1015 nobj += thdr.enc_maxelt; 1016 } 1017 1018 1019 /* 1020 * Now allocate the object array and type map. 1021 */ 1022 1023 ssc->ses_objmap = SES_MALLOC(nobj * sizeof (encobj)); 1024 cc->ses_typidx = SES_MALLOC(nobj * sizeof (struct typidx)); 1025 cc->ses_eltmap = SES_MALLOC(ntype); 1026 1027 if (ssc->ses_objmap == NULL || cc->ses_typidx == NULL || 1028 cc->ses_eltmap == NULL) { 1029 if (ssc->ses_objmap) { 1030 SES_FREE(ssc->ses_objmap, (nobj * sizeof (encobj))); 1031 ssc->ses_objmap = NULL; 1032 } 1033 if (cc->ses_typidx) { 1034 SES_FREE(cc->ses_typidx, 1035 (nobj * sizeof (struct typidx))); 1036 cc->ses_typidx = NULL; 1037 } 1038 if (cc->ses_eltmap) { 1039 SES_FREE(cc->ses_eltmap, ntype); 1040 cc->ses_eltmap = NULL; 1041 } 1042 SES_FREE(sdata, SCSZ); 1043 return (ENOMEM); 1044 } 1045 MEMZERO(ssc->ses_objmap, nobj * sizeof (encobj)); 1046 MEMZERO(cc->ses_typidx, nobj * sizeof (struct typidx)); 1047 MEMZERO(cc->ses_eltmap, ntype); 1048 cc->ses_ntypes = (uint8_t) ntype; 1049 ssc->ses_nobjects = nobj; 1050 1051 /* 1052 * Now waltz through the # of types again to fill in the types 1053 * (and subenclosure ids) of the allocated objects. 1054 */ 1055 nobj = 0; 1056 for (i = 0; i < ntype; i++) { 1057 int j; 1058 if (ses_getthdr((uint8_t *)sdata, amt, i, &thdr)) { 1059 continue; 1060 } 1061 cc->ses_eltmap[i] = thdr.enc_maxelt; 1062 for (j = 0; j < thdr.enc_maxelt; j++) { 1063 cc->ses_typidx[nobj].ses_tidx = i; 1064 cc->ses_typidx[nobj].ses_oidx = j; 1065 ssc->ses_objmap[nobj].subenclosure = thdr.enc_subenc; 1066 ssc->ses_objmap[nobj++].enctype = thdr.enc_type; 1067 } 1068 } 1069 SES_FREE(sdata, SCSZ); 1070 return (0); 1071 } 1072 1073 static int 1074 ses_getputstat(ses_softc_t *ssc, int objid, SesComStat *sp, int slp, 1075 int in) 1076 { 1077 struct sscfg *cc; 1078 int err, amt, bufsiz, tidx, oidx; 1079 char cdb[6], *sdata; 1080 1081 cc = ssc->ses_private; 1082 if (cc == NULL) { 1083 return (ENXIO); 1084 } 1085 1086 /* 1087 * If we're just getting overall enclosure status, 1088 * we only need 2 bytes of data storage. 1089 * 1090 * If we're getting anything else, we know how much 1091 * storage we need by noting that starting at offset 1092 * 8 in returned data, all object status bytes are 4 1093 * bytes long, and are stored in chunks of types(M) 1094 * and nth+1 instances of type M. 1095 */ 1096 if (objid == -1) { 1097 bufsiz = 2; 1098 } else { 1099 bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8; 1100 } 1101 sdata = SES_MALLOC(bufsiz); 1102 if (sdata == NULL) 1103 return (ENOMEM); 1104 1105 cdb[0] = RECEIVE_DIAGNOSTIC; 1106 cdb[1] = 1; 1107 cdb[2] = SesStatusPage; 1108 cdb[3] = bufsiz >> 8; 1109 cdb[4] = bufsiz & 0xff; 1110 cdb[5] = 0; 1111 amt = bufsiz; 1112 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1113 if (err) { 1114 SES_FREE(sdata, bufsiz); 1115 return (err); 1116 } 1117 amt = bufsiz - amt; 1118 1119 if (objid == -1) { 1120 tidx = -1; 1121 oidx = -1; 1122 } else { 1123 tidx = cc->ses_typidx[objid].ses_tidx; 1124 oidx = cc->ses_typidx[objid].ses_oidx; 1125 } 1126 if (in) { 1127 if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1128 err = ENODEV; 1129 } 1130 } else { 1131 if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1132 err = ENODEV; 1133 } else { 1134 cdb[0] = SEND_DIAGNOSTIC; 1135 cdb[1] = 0x10; 1136 cdb[2] = 0; 1137 cdb[3] = bufsiz >> 8; 1138 cdb[4] = bufsiz & 0xff; 1139 cdb[5] = 0; 1140 amt = -bufsiz; 1141 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1142 } 1143 } 1144 SES_FREE(sdata, bufsiz); 1145 return (0); 1146 } 1147 1148 1149 /* 1150 * Routines to parse returned SES data structures. 1151 * Architecture and compiler independent. 1152 */ 1153 1154 static int 1155 ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp) 1156 { 1157 if (buflen < SES_CFGHDR_MINLEN) { 1158 return (-1); 1159 } 1160 gget8(buffer, 1, cfp->Nsubenc); 1161 gget32(buffer, 4, cfp->GenCode); 1162 return (0); 1163 } 1164 1165 static int 1166 ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp) 1167 { 1168 int s, off = 8; 1169 for (s = 0; s < SubEncId; s++) { 1170 if (off + 3 > amt) 1171 return (-1); 1172 off += buffer[off+3] + 4; 1173 } 1174 if (off + 3 > amt) { 1175 return (-1); 1176 } 1177 gget8(buffer, off+1, chp->Subencid); 1178 gget8(buffer, off+2, chp->Ntypes); 1179 gget8(buffer, off+3, chp->VEnclen); 1180 return (0); 1181 } 1182 1183 static int 1184 ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp) 1185 { 1186 int s, e, enclen, off = 8; 1187 for (s = 0; s < SubEncId; s++) { 1188 if (off + 3 > amt) 1189 return (-1); 1190 off += buffer[off+3] + 4; 1191 } 1192 if (off + 3 > amt) { 1193 return (-1); 1194 } 1195 gget8(buffer, off+3, enclen); 1196 off += 4; 1197 if (off >= amt) 1198 return (-1); 1199 1200 e = off + enclen; 1201 if (e > amt) { 1202 e = amt; 1203 } 1204 MEMCPY(cdp, &buffer[off], e - off); 1205 return (0); 1206 } 1207 1208 static int 1209 ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp) 1210 { 1211 int s, off = 8; 1212 1213 if (amt < SES_CFGHDR_MINLEN) { 1214 return (-1); 1215 } 1216 for (s = 0; s < buffer[1]; s++) { 1217 if (off + 3 > amt) 1218 return (-1); 1219 off += buffer[off+3] + 4; 1220 } 1221 if (off + 3 > amt) { 1222 return (-1); 1223 } 1224 off += buffer[off+3] + 4 + (nth * 4); 1225 if (amt < (off + 4)) 1226 return (-1); 1227 1228 gget8(buffer, off++, thp->enc_type); 1229 gget8(buffer, off++, thp->enc_maxelt); 1230 gget8(buffer, off++, thp->enc_subenc); 1231 gget8(buffer, off, thp->enc_tlen); 1232 return (0); 1233 } 1234 1235 /* 1236 * This function needs a little explanation. 1237 * 1238 * The arguments are: 1239 * 1240 * 1241 * char *b, int amt 1242 * 1243 * These describes the raw input SES status data and length. 1244 * 1245 * uint8_t *ep 1246 * 1247 * This is a map of the number of types for each element type 1248 * in the enclosure. 1249 * 1250 * int elt 1251 * 1252 * This is the element type being sought. If elt is -1, 1253 * then overall enclosure status is being sought. 1254 * 1255 * int elm 1256 * 1257 * This is the ordinal Mth element of type elt being sought. 1258 * 1259 * SesComStat *sp 1260 * 1261 * This is the output area to store the status for 1262 * the Mth element of type Elt. 1263 */ 1264 1265 static int 1266 ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1267 { 1268 int idx, i; 1269 1270 /* 1271 * If it's overall enclosure status being sought, get that. 1272 * We need at least 2 bytes of status data to get that. 1273 */ 1274 if (elt == -1) { 1275 if (amt < 2) 1276 return (-1); 1277 gget8(b, 1, sp->comstatus); 1278 sp->comstat[0] = 0; 1279 sp->comstat[1] = 0; 1280 sp->comstat[2] = 0; 1281 return (0); 1282 } 1283 1284 /* 1285 * Check to make sure that the Mth element is legal for type Elt. 1286 */ 1287 1288 if (elm >= ep[elt]) 1289 return (-1); 1290 1291 /* 1292 * Starting at offset 8, start skipping over the storage 1293 * for the element types we're not interested in. 1294 */ 1295 for (idx = 8, i = 0; i < elt; i++) { 1296 idx += ((ep[i] + 1) * 4); 1297 } 1298 1299 /* 1300 * Skip over Overall status for this element type. 1301 */ 1302 idx += 4; 1303 1304 /* 1305 * And skip to the index for the Mth element that we're going for. 1306 */ 1307 idx += (4 * elm); 1308 1309 /* 1310 * Make sure we haven't overflowed the buffer. 1311 */ 1312 if (idx+4 > amt) 1313 return (-1); 1314 1315 /* 1316 * Retrieve the status. 1317 */ 1318 gget8(b, idx++, sp->comstatus); 1319 gget8(b, idx++, sp->comstat[0]); 1320 gget8(b, idx++, sp->comstat[1]); 1321 gget8(b, idx++, sp->comstat[2]); 1322 #if 0 1323 PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4); 1324 #endif 1325 return (0); 1326 } 1327 1328 /* 1329 * This is the mirror function to ses_decode, but we set the 'select' 1330 * bit for the object which we're interested in. All other objects, 1331 * after a status fetch, should have that bit off. Hmm. It'd be easy 1332 * enough to ensure this, so we will. 1333 */ 1334 1335 static int 1336 ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1337 { 1338 int idx, i; 1339 1340 /* 1341 * If it's overall enclosure status being sought, get that. 1342 * We need at least 2 bytes of status data to get that. 1343 */ 1344 if (elt == -1) { 1345 if (amt < 2) 1346 return (-1); 1347 i = 0; 1348 sset8(b, i, 0); 1349 sset8(b, i, sp->comstatus & 0xf); 1350 #if 0 1351 PRINTF("set EncStat %x\n", sp->comstatus); 1352 #endif 1353 return (0); 1354 } 1355 1356 /* 1357 * Check to make sure that the Mth element is legal for type Elt. 1358 */ 1359 1360 if (elm >= ep[elt]) 1361 return (-1); 1362 1363 /* 1364 * Starting at offset 8, start skipping over the storage 1365 * for the element types we're not interested in. 1366 */ 1367 for (idx = 8, i = 0; i < elt; i++) { 1368 idx += ((ep[i] + 1) * 4); 1369 } 1370 1371 /* 1372 * Skip over Overall status for this element type. 1373 */ 1374 idx += 4; 1375 1376 /* 1377 * And skip to the index for the Mth element that we're going for. 1378 */ 1379 idx += (4 * elm); 1380 1381 /* 1382 * Make sure we haven't overflowed the buffer. 1383 */ 1384 if (idx+4 > amt) 1385 return (-1); 1386 1387 /* 1388 * Set the status. 1389 */ 1390 sset8(b, idx, sp->comstatus); 1391 sset8(b, idx, sp->comstat[0]); 1392 sset8(b, idx, sp->comstat[1]); 1393 sset8(b, idx, sp->comstat[2]); 1394 idx -= 4; 1395 1396 #if 0 1397 PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n", 1398 elt, elm, idx, sp->comstatus, sp->comstat[0], 1399 sp->comstat[1], sp->comstat[2]); 1400 #endif 1401 1402 /* 1403 * Now make sure all other 'Select' bits are off. 1404 */ 1405 for (i = 8; i < amt; i += 4) { 1406 if (i != idx) 1407 b[i] &= ~0x80; 1408 } 1409 /* 1410 * And make sure the INVOP bit is clear. 1411 */ 1412 b[2] &= ~0x10; 1413 1414 return (0); 1415 } 1416 1417 /* 1418 * SAF-TE Type Device Emulation 1419 */ 1420 1421 static int safte_getconfig(ses_softc_t *); 1422 static int safte_rdstat(ses_softc_t *, int); 1423 static int set_objstat_sel(ses_softc_t *, ses_objstat *, int); 1424 static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int); 1425 static void wrslot_stat(ses_softc_t *, int); 1426 static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int); 1427 1428 #define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \ 1429 SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) 1430 /* 1431 * SAF-TE specific defines- Mandatory ones only... 1432 */ 1433 1434 /* 1435 * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb 1436 */ 1437 #define SAFTE_RD_RDCFG 0x00 /* read enclosure configuration */ 1438 #define SAFTE_RD_RDESTS 0x01 /* read enclosure status */ 1439 #define SAFTE_RD_RDDSTS 0x04 /* read drive slot status */ 1440 1441 /* 1442 * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf 1443 */ 1444 #define SAFTE_WT_DSTAT 0x10 /* write device slot status */ 1445 #define SAFTE_WT_SLTOP 0x12 /* perform slot operation */ 1446 #define SAFTE_WT_FANSPD 0x13 /* set fan speed */ 1447 #define SAFTE_WT_ACTPWS 0x14 /* turn on/off power supply */ 1448 #define SAFTE_WT_GLOBAL 0x15 /* send global command */ 1449 1450 1451 #define SAFT_SCRATCH 64 1452 #define NPSEUDO_THERM 16 1453 #define NPSEUDO_ALARM 1 1454 struct scfg { 1455 /* 1456 * Cached Configuration 1457 */ 1458 uint8_t Nfans; /* Number of Fans */ 1459 uint8_t Npwr; /* Number of Power Supplies */ 1460 uint8_t Nslots; /* Number of Device Slots */ 1461 uint8_t DoorLock; /* Door Lock Installed */ 1462 uint8_t Ntherm; /* Number of Temperature Sensors */ 1463 uint8_t Nspkrs; /* Number of Speakers */ 1464 uint8_t Nalarm; /* Number of Alarms (at least one) */ 1465 /* 1466 * Cached Flag Bytes for Global Status 1467 */ 1468 uint8_t flag1; 1469 uint8_t flag2; 1470 /* 1471 * What object index ID is where various slots start. 1472 */ 1473 uint8_t pwroff; 1474 uint8_t slotoff; 1475 #define SAFT_ALARM_OFFSET(cc) (cc)->slotoff - 1 1476 }; 1477 1478 #define SAFT_FLG1_ALARM 0x1 1479 #define SAFT_FLG1_GLOBFAIL 0x2 1480 #define SAFT_FLG1_GLOBWARN 0x4 1481 #define SAFT_FLG1_ENCPWROFF 0x8 1482 #define SAFT_FLG1_ENCFANFAIL 0x10 1483 #define SAFT_FLG1_ENCPWRFAIL 0x20 1484 #define SAFT_FLG1_ENCDRVFAIL 0x40 1485 #define SAFT_FLG1_ENCDRVWARN 0x80 1486 1487 #define SAFT_FLG2_LOCKDOOR 0x4 1488 #define SAFT_PRIVATE sizeof (struct scfg) 1489 1490 static const char safte_2little[] = "Too Little Data Returned (%d) at line %d\n"; 1491 #define SAFT_BAIL(r, x, k, l) \ 1492 if (r >= x) { \ 1493 SES_LOG(ssc, safte_2little, x, __LINE__);\ 1494 SES_FREE(k, l); \ 1495 return (EIO); \ 1496 } 1497 1498 1499 static int 1500 safte_softc_init(ses_softc_t *ssc, int doinit) 1501 { 1502 int err, i, r; 1503 struct scfg *cc; 1504 1505 if (doinit == 0) { 1506 if (ssc->ses_nobjects) { 1507 if (ssc->ses_objmap) { 1508 SES_FREE(ssc->ses_objmap, 1509 ssc->ses_nobjects * sizeof (encobj)); 1510 ssc->ses_objmap = NULL; 1511 } 1512 ssc->ses_nobjects = 0; 1513 } 1514 if (ssc->ses_private) { 1515 SES_FREE(ssc->ses_private, SAFT_PRIVATE); 1516 ssc->ses_private = NULL; 1517 } 1518 return (0); 1519 } 1520 1521 if (ssc->ses_private == NULL) { 1522 ssc->ses_private = SES_MALLOC(SAFT_PRIVATE); 1523 if (ssc->ses_private == NULL) { 1524 return (ENOMEM); 1525 } 1526 MEMZERO(ssc->ses_private, SAFT_PRIVATE); 1527 } 1528 1529 ssc->ses_nobjects = 0; 1530 ssc->ses_encstat = 0; 1531 1532 if ((err = safte_getconfig(ssc)) != 0) { 1533 return (err); 1534 } 1535 1536 /* 1537 * The number of objects here, as well as that reported by the 1538 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15) 1539 * that get reported during READ_BUFFER/READ_ENC_STATUS. 1540 */ 1541 cc = ssc->ses_private; 1542 ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock + 1543 cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM; 1544 ssc->ses_objmap = (encobj *) 1545 SES_MALLOC(ssc->ses_nobjects * sizeof (encobj)); 1546 if (ssc->ses_objmap == NULL) { 1547 return (ENOMEM); 1548 } 1549 MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj)); 1550 1551 r = 0; 1552 /* 1553 * Note that this is all arranged for the convenience 1554 * in later fetches of status. 1555 */ 1556 for (i = 0; i < cc->Nfans; i++) 1557 ssc->ses_objmap[r++].enctype = SESTYP_FAN; 1558 cc->pwroff = (uint8_t) r; 1559 for (i = 0; i < cc->Npwr; i++) 1560 ssc->ses_objmap[r++].enctype = SESTYP_POWER; 1561 for (i = 0; i < cc->DoorLock; i++) 1562 ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK; 1563 for (i = 0; i < cc->Nspkrs; i++) 1564 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1565 for (i = 0; i < cc->Ntherm; i++) 1566 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1567 for (i = 0; i < NPSEUDO_THERM; i++) 1568 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1569 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1570 cc->slotoff = (uint8_t) r; 1571 for (i = 0; i < cc->Nslots; i++) 1572 ssc->ses_objmap[r++].enctype = SESTYP_DEVICE; 1573 return (0); 1574 } 1575 1576 static int 1577 safte_init_enc(ses_softc_t *ssc) 1578 { 1579 int err, amt; 1580 char *sdata; 1581 static char cdb0[6] = { SEND_DIAGNOSTIC }; 1582 static char cdb[10] = 1583 { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 }; 1584 1585 sdata = SES_MALLOC(SAFT_SCRATCH); 1586 if (sdata == NULL) 1587 return (ENOMEM); 1588 1589 err = ses_runcmd(ssc, cdb0, 6, NULL, 0); 1590 if (err) { 1591 SES_FREE(sdata, SAFT_SCRATCH); 1592 return (err); 1593 } 1594 sdata[0] = SAFTE_WT_GLOBAL; 1595 MEMZERO(&sdata[1], 15); 1596 amt = -SAFT_SCRATCH; 1597 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1598 SES_FREE(sdata, SAFT_SCRATCH); 1599 return (err); 1600 } 1601 1602 static int 1603 safte_get_encstat(ses_softc_t *ssc, int slpflg) 1604 { 1605 return (safte_rdstat(ssc, slpflg)); 1606 } 1607 1608 static int 1609 safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg) 1610 { 1611 struct scfg *cc = ssc->ses_private; 1612 if (cc == NULL) 1613 return (0); 1614 /* 1615 * Since SAF-TE devices aren't necessarily sticky in terms 1616 * of state, make our soft copy of enclosure status 'sticky'- 1617 * that is, things set in enclosure status stay set (as implied 1618 * by conditions set in reading object status) until cleared. 1619 */ 1620 ssc->ses_encstat &= ~ALL_ENC_STAT; 1621 ssc->ses_encstat |= (encstat & ALL_ENC_STAT); 1622 ssc->ses_encstat |= ENCI_SVALID; 1623 cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN); 1624 if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) { 1625 cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL; 1626 } else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) { 1627 cc->flag1 |= SAFT_FLG1_GLOBWARN; 1628 } 1629 return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg)); 1630 } 1631 1632 static int 1633 safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg) 1634 { 1635 int i = (int)obp->obj_id; 1636 1637 if ((ssc->ses_encstat & ENCI_SVALID) == 0 || 1638 (ssc->ses_objmap[i].svalid) == 0) { 1639 int err = safte_rdstat(ssc, slpflg); 1640 if (err) 1641 return (err); 1642 } 1643 obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; 1644 obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; 1645 obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; 1646 obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; 1647 return (0); 1648 } 1649 1650 1651 static int 1652 safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp) 1653 { 1654 int idx, err; 1655 encobj *ep; 1656 struct scfg *cc; 1657 1658 1659 SES_VLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n", 1660 (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2], 1661 obp->cstat[3]); 1662 1663 /* 1664 * If this is clear, we don't do diddly. 1665 */ 1666 if ((obp->cstat[0] & SESCTL_CSEL) == 0) { 1667 return (0); 1668 } 1669 1670 err = 0; 1671 /* 1672 * Check to see if the common bits are set and do them first. 1673 */ 1674 if (obp->cstat[0] & ~SESCTL_CSEL) { 1675 err = set_objstat_sel(ssc, obp, slp); 1676 if (err) 1677 return (err); 1678 } 1679 1680 cc = ssc->ses_private; 1681 if (cc == NULL) 1682 return (0); 1683 1684 idx = (int)obp->obj_id; 1685 ep = &ssc->ses_objmap[idx]; 1686 1687 switch (ep->enctype) { 1688 case SESTYP_DEVICE: 1689 { 1690 uint8_t slotop = 0; 1691 /* 1692 * XXX: I should probably cache the previous state 1693 * XXX: of SESCTL_DEVOFF so that when it goes from 1694 * XXX: true to false I can then set PREPARE FOR OPERATION 1695 * XXX: flag in PERFORM SLOT OPERATION write buffer command. 1696 */ 1697 if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) { 1698 slotop |= 0x2; 1699 } 1700 if (obp->cstat[2] & SESCTL_RQSID) { 1701 slotop |= 0x4; 1702 } 1703 err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff, 1704 slotop, slp); 1705 if (err) 1706 return (err); 1707 if (obp->cstat[3] & SESCTL_RQSFLT) { 1708 ep->priv |= 0x2; 1709 } else { 1710 ep->priv &= ~0x2; 1711 } 1712 if (ep->priv & 0xc6) { 1713 ep->priv &= ~0x1; 1714 } else { 1715 ep->priv |= 0x1; /* no errors */ 1716 } 1717 wrslot_stat(ssc, slp); 1718 break; 1719 } 1720 case SESTYP_POWER: 1721 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1722 cc->flag1 |= SAFT_FLG1_ENCPWRFAIL; 1723 } else { 1724 cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL; 1725 } 1726 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1727 cc->flag2, 0, slp); 1728 if (err) 1729 return (err); 1730 if (obp->cstat[3] & SESCTL_RQSTON) { 1731 (void) wrbuf16(ssc, SAFTE_WT_ACTPWS, 1732 idx - cc->pwroff, 0, 0, slp); 1733 } else { 1734 (void) wrbuf16(ssc, SAFTE_WT_ACTPWS, 1735 idx - cc->pwroff, 0, 1, slp); 1736 } 1737 break; 1738 case SESTYP_FAN: 1739 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1740 cc->flag1 |= SAFT_FLG1_ENCFANFAIL; 1741 } else { 1742 cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL; 1743 } 1744 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1745 cc->flag2, 0, slp); 1746 if (err) 1747 return (err); 1748 if (obp->cstat[3] & SESCTL_RQSTON) { 1749 uint8_t fsp; 1750 if ((obp->cstat[3] & 0x7) == 7) { 1751 fsp = 4; 1752 } else if ((obp->cstat[3] & 0x7) == 6) { 1753 fsp = 3; 1754 } else if ((obp->cstat[3] & 0x7) == 4) { 1755 fsp = 2; 1756 } else { 1757 fsp = 1; 1758 } 1759 (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp); 1760 } else { 1761 (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 1762 } 1763 break; 1764 case SESTYP_DOORLOCK: 1765 if (obp->cstat[3] & 0x1) { 1766 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 1767 } else { 1768 cc->flag2 |= SAFT_FLG2_LOCKDOOR; 1769 } 1770 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1771 cc->flag2, 0, slp); 1772 break; 1773 case SESTYP_ALARM: 1774 /* 1775 * On all nonzero but the 'muted' bit, we turn on the alarm, 1776 */ 1777 obp->cstat[3] &= ~0xa; 1778 if (obp->cstat[3] & 0x40) { 1779 cc->flag2 &= ~SAFT_FLG1_ALARM; 1780 } else if (obp->cstat[3] != 0) { 1781 cc->flag2 |= SAFT_FLG1_ALARM; 1782 } else { 1783 cc->flag2 &= ~SAFT_FLG1_ALARM; 1784 } 1785 ep->priv = obp->cstat[3]; 1786 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1787 cc->flag2, 0, slp); 1788 break; 1789 default: 1790 break; 1791 } 1792 ep->svalid = 0; 1793 return (0); 1794 } 1795 1796 static int 1797 safte_getconfig(ses_softc_t *ssc) 1798 { 1799 struct scfg *cfg; 1800 int err, amt; 1801 char *sdata; 1802 static char cdb[10] = 1803 { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 1804 1805 cfg = ssc->ses_private; 1806 if (cfg == NULL) 1807 return (ENXIO); 1808 1809 sdata = SES_MALLOC(SAFT_SCRATCH); 1810 if (sdata == NULL) 1811 return (ENOMEM); 1812 1813 amt = SAFT_SCRATCH; 1814 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1815 if (err) { 1816 SES_FREE(sdata, SAFT_SCRATCH); 1817 return (err); 1818 } 1819 amt = SAFT_SCRATCH - amt; 1820 if (amt < 6) { 1821 SES_LOG(ssc, "too little data (%d) for configuration\n", amt); 1822 SES_FREE(sdata, SAFT_SCRATCH); 1823 return (EIO); 1824 } 1825 SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n", 1826 sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); 1827 cfg->Nfans = sdata[0]; 1828 cfg->Npwr = sdata[1]; 1829 cfg->Nslots = sdata[2]; 1830 cfg->DoorLock = sdata[3]; 1831 cfg->Ntherm = sdata[4]; 1832 cfg->Nspkrs = sdata[5]; 1833 cfg->Nalarm = NPSEUDO_ALARM; 1834 SES_FREE(sdata, SAFT_SCRATCH); 1835 return (0); 1836 } 1837 1838 static int 1839 safte_rdstat(ses_softc_t *ssc, int slpflg) 1840 { 1841 int err, oid, r, i, hiwater, nitems, amt; 1842 uint16_t tempflags; 1843 size_t buflen; 1844 uint8_t status, oencstat; 1845 char *sdata, cdb[10]; 1846 struct scfg *cc = ssc->ses_private; 1847 1848 1849 /* 1850 * The number of objects overstates things a bit, 1851 * both for the bogus 'thermometer' entries and 1852 * the drive status (which isn't read at the same 1853 * time as the enclosure status), but that's okay. 1854 */ 1855 buflen = 4 * cc->Nslots; 1856 if (ssc->ses_nobjects > buflen) 1857 buflen = ssc->ses_nobjects; 1858 sdata = SES_MALLOC(buflen); 1859 if (sdata == NULL) 1860 return (ENOMEM); 1861 1862 cdb[0] = READ_BUFFER; 1863 cdb[1] = 1; 1864 cdb[2] = SAFTE_RD_RDESTS; 1865 cdb[3] = 0; 1866 cdb[4] = 0; 1867 cdb[5] = 0; 1868 cdb[6] = 0; 1869 cdb[7] = (buflen >> 8) & 0xff; 1870 cdb[8] = buflen & 0xff; 1871 cdb[9] = 0; 1872 amt = buflen; 1873 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1874 if (err) { 1875 SES_FREE(sdata, buflen); 1876 return (err); 1877 } 1878 hiwater = buflen - amt; 1879 1880 1881 /* 1882 * invalidate all status bits. 1883 */ 1884 for (i = 0; i < ssc->ses_nobjects; i++) 1885 ssc->ses_objmap[i].svalid = 0; 1886 oencstat = ssc->ses_encstat & ALL_ENC_STAT; 1887 ssc->ses_encstat = 0; 1888 1889 1890 /* 1891 * Now parse returned buffer. 1892 * If we didn't get enough data back, 1893 * that's considered a fatal error. 1894 */ 1895 oid = r = 0; 1896 1897 for (nitems = i = 0; i < cc->Nfans; i++) { 1898 SAFT_BAIL(r, hiwater, sdata, buflen); 1899 /* 1900 * 0 = Fan Operational 1901 * 1 = Fan is malfunctioning 1902 * 2 = Fan is not present 1903 * 0x80 = Unknown or Not Reportable Status 1904 */ 1905 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 1906 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 1907 switch ((int)(uint8_t)sdata[r]) { 1908 case 0: 1909 nitems++; 1910 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 1911 /* 1912 * We could get fancier and cache 1913 * fan speeds that we have set, but 1914 * that isn't done now. 1915 */ 1916 ssc->ses_objmap[oid].encstat[3] = 7; 1917 break; 1918 1919 case 1: 1920 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 1921 /* 1922 * FAIL and FAN STOPPED synthesized 1923 */ 1924 ssc->ses_objmap[oid].encstat[3] = 0x40; 1925 /* 1926 * Enclosure marked with CRITICAL error 1927 * if only one fan or no thermometers, 1928 * else the NONCRITICAL error is set. 1929 */ 1930 if (cc->Nfans == 1 || cc->Ntherm == 0) 1931 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 1932 else 1933 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 1934 break; 1935 case 2: 1936 ssc->ses_objmap[oid].encstat[0] = 1937 SES_OBJSTAT_NOTINSTALLED; 1938 ssc->ses_objmap[oid].encstat[3] = 0; 1939 /* 1940 * Enclosure marked with CRITICAL error 1941 * if only one fan or no thermometers, 1942 * else the NONCRITICAL error is set. 1943 */ 1944 if (cc->Nfans == 1) 1945 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 1946 else 1947 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 1948 break; 1949 case 0x80: 1950 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 1951 ssc->ses_objmap[oid].encstat[3] = 0; 1952 ssc->ses_encstat |= SES_ENCSTAT_INFO; 1953 break; 1954 default: 1955 ssc->ses_objmap[oid].encstat[0] = 1956 SES_OBJSTAT_UNSUPPORTED; 1957 SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i, 1958 sdata[r] & 0xff); 1959 break; 1960 } 1961 ssc->ses_objmap[oid++].svalid = 1; 1962 r++; 1963 } 1964 1965 /* 1966 * No matter how you cut it, no cooling elements when there 1967 * should be some there is critical. 1968 */ 1969 if (cc->Nfans && nitems == 0) { 1970 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 1971 } 1972 1973 1974 for (i = 0; i < cc->Npwr; i++) { 1975 SAFT_BAIL(r, hiwater, sdata, buflen); 1976 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 1977 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 1978 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 1979 ssc->ses_objmap[oid].encstat[3] = 0x20; /* requested on */ 1980 switch ((uint8_t)sdata[r]) { 1981 case 0x00: /* pws operational and on */ 1982 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 1983 break; 1984 case 0x01: /* pws operational and off */ 1985 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 1986 ssc->ses_objmap[oid].encstat[3] = 0x10; 1987 ssc->ses_encstat |= SES_ENCSTAT_INFO; 1988 break; 1989 case 0x10: /* pws is malfunctioning and commanded on */ 1990 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 1991 ssc->ses_objmap[oid].encstat[3] = 0x61; 1992 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 1993 break; 1994 1995 case 0x11: /* pws is malfunctioning and commanded off */ 1996 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 1997 ssc->ses_objmap[oid].encstat[3] = 0x51; 1998 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 1999 break; 2000 case 0x20: /* pws is not present */ 2001 ssc->ses_objmap[oid].encstat[0] = 2002 SES_OBJSTAT_NOTINSTALLED; 2003 ssc->ses_objmap[oid].encstat[3] = 0; 2004 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2005 break; 2006 case 0x21: /* pws is present */ 2007 /* 2008 * This is for enclosures that cannot tell whether the 2009 * device is on or malfunctioning, but know that it is 2010 * present. Just fall through. 2011 */ 2012 /* FALLTHROUGH */ 2013 case 0x80: /* Unknown or Not Reportable Status */ 2014 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2015 ssc->ses_objmap[oid].encstat[3] = 0; 2016 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2017 break; 2018 default: 2019 SES_LOG(ssc, "unknown power supply %d status (0x%x)\n", 2020 i, sdata[r] & 0xff); 2021 break; 2022 } 2023 ssc->ses_objmap[oid++].svalid = 1; 2024 r++; 2025 } 2026 2027 /* 2028 * Skip over Slot SCSI IDs 2029 */ 2030 r += cc->Nslots; 2031 2032 /* 2033 * We always have doorlock status, no matter what, 2034 * but we only save the status if we have one. 2035 */ 2036 SAFT_BAIL(r, hiwater, sdata, buflen); 2037 if (cc->DoorLock) { 2038 /* 2039 * 0 = Door Locked 2040 * 1 = Door Unlocked, or no Lock Installed 2041 * 0x80 = Unknown or Not Reportable Status 2042 */ 2043 ssc->ses_objmap[oid].encstat[1] = 0; 2044 ssc->ses_objmap[oid].encstat[2] = 0; 2045 switch ((uint8_t)sdata[r]) { 2046 case 0: 2047 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2048 ssc->ses_objmap[oid].encstat[3] = 0; 2049 break; 2050 case 1: 2051 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2052 ssc->ses_objmap[oid].encstat[3] = 1; 2053 break; 2054 case 0x80: 2055 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2056 ssc->ses_objmap[oid].encstat[3] = 0; 2057 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2058 break; 2059 default: 2060 ssc->ses_objmap[oid].encstat[0] = 2061 SES_OBJSTAT_UNSUPPORTED; 2062 SES_LOG(ssc, "unknown lock status 0x%x\n", 2063 sdata[r] & 0xff); 2064 break; 2065 } 2066 ssc->ses_objmap[oid++].svalid = 1; 2067 } 2068 r++; 2069 2070 /* 2071 * We always have speaker status, no matter what, 2072 * but we only save the status if we have one. 2073 */ 2074 SAFT_BAIL(r, hiwater, sdata, buflen); 2075 if (cc->Nspkrs) { 2076 ssc->ses_objmap[oid].encstat[1] = 0; 2077 ssc->ses_objmap[oid].encstat[2] = 0; 2078 if (sdata[r] == 1) { 2079 /* 2080 * We need to cache tone urgency indicators. 2081 * Someday. 2082 */ 2083 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 2084 ssc->ses_objmap[oid].encstat[3] = 0x8; 2085 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2086 } else if (sdata[r] == 0) { 2087 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2088 ssc->ses_objmap[oid].encstat[3] = 0; 2089 } else { 2090 ssc->ses_objmap[oid].encstat[0] = 2091 SES_OBJSTAT_UNSUPPORTED; 2092 ssc->ses_objmap[oid].encstat[3] = 0; 2093 SES_LOG(ssc, "unknown spkr status 0x%x\n", 2094 sdata[r] & 0xff); 2095 } 2096 ssc->ses_objmap[oid++].svalid = 1; 2097 } 2098 r++; 2099 2100 for (i = 0; i < cc->Ntherm; i++) { 2101 SAFT_BAIL(r, hiwater, sdata, buflen); 2102 /* 2103 * Status is a range from -10 to 245 deg Celsius, 2104 * which we need to normalize to -20 to -245 according 2105 * to the latest SCSI spec, which makes little 2106 * sense since this would overflow an 8bit value. 2107 * Well, still, the base normalization is -20, 2108 * not -10, so we have to adjust. 2109 * 2110 * So what's over and under temperature? 2111 * Hmm- we'll state that 'normal' operating 2112 * is 10 to 40 deg Celsius. 2113 */ 2114 2115 /* 2116 * Actually.... All of the units that people out in the world 2117 * seem to have do not come even close to setting a value that 2118 * complies with this spec. 2119 * 2120 * The closest explanation I could find was in an 2121 * LSI-Logic manual, which seemed to indicate that 2122 * this value would be set by whatever the I2C code 2123 * would interpolate from the output of an LM75 2124 * temperature sensor. 2125 * 2126 * This means that it is impossible to use the actual 2127 * numeric value to predict anything. But we don't want 2128 * to lose the value. So, we'll propagate the *uncorrected* 2129 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the 2130 * temperature flags for warnings. 2131 */ 2132 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL; 2133 ssc->ses_objmap[oid].encstat[1] = 0; 2134 ssc->ses_objmap[oid].encstat[2] = sdata[r]; 2135 ssc->ses_objmap[oid].encstat[3] = 0; 2136 ssc->ses_objmap[oid++].svalid = 1; 2137 r++; 2138 } 2139 2140 /* 2141 * Now, for "pseudo" thermometers, we have two bytes 2142 * of information in enclosure status- 16 bits. Actually, 2143 * the MSB is a single TEMP ALERT flag indicating whether 2144 * any other bits are set, but, thanks to fuzzy thinking, 2145 * in the SAF-TE spec, this can also be set even if no 2146 * other bits are set, thus making this really another 2147 * binary temperature sensor. 2148 */ 2149 2150 SAFT_BAIL(r, hiwater, sdata, buflen); 2151 tempflags = sdata[r++]; 2152 SAFT_BAIL(r, hiwater, sdata, buflen); 2153 tempflags |= (tempflags << 8) | sdata[r++]; 2154 2155 for (i = 0; i < NPSEUDO_THERM; i++) { 2156 ssc->ses_objmap[oid].encstat[1] = 0; 2157 if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) { 2158 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2159 ssc->ses_objmap[4].encstat[2] = 0xff; 2160 /* 2161 * Set 'over temperature' failure. 2162 */ 2163 ssc->ses_objmap[oid].encstat[3] = 8; 2164 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2165 } else { 2166 /* 2167 * We used to say 'not available' and synthesize a 2168 * nominal 30 deg (C)- that was wrong. Actually, 2169 * Just say 'OK', and use the reserved value of 2170 * zero. 2171 */ 2172 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2173 ssc->ses_objmap[oid].encstat[2] = 0; 2174 ssc->ses_objmap[oid].encstat[3] = 0; 2175 } 2176 ssc->ses_objmap[oid++].svalid = 1; 2177 } 2178 2179 /* 2180 * Get alarm status. 2181 */ 2182 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2183 ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv; 2184 ssc->ses_objmap[oid++].svalid = 1; 2185 2186 /* 2187 * Now get drive slot status 2188 */ 2189 cdb[2] = SAFTE_RD_RDDSTS; 2190 amt = buflen; 2191 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2192 if (err) { 2193 SES_FREE(sdata, buflen); 2194 return (err); 2195 } 2196 hiwater = buflen - amt; 2197 for (r = i = 0; i < cc->Nslots; i++, r += 4) { 2198 SAFT_BAIL(r+3, hiwater, sdata, buflen); 2199 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED; 2200 ssc->ses_objmap[oid].encstat[1] = (uint8_t) i; 2201 ssc->ses_objmap[oid].encstat[2] = 0; 2202 ssc->ses_objmap[oid].encstat[3] = 0; 2203 status = sdata[r+3]; 2204 if ((status & 0x1) == 0) { /* no device */ 2205 ssc->ses_objmap[oid].encstat[0] = 2206 SES_OBJSTAT_NOTINSTALLED; 2207 } else { 2208 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2209 } 2210 if (status & 0x2) { 2211 ssc->ses_objmap[oid].encstat[2] = 0x8; 2212 } 2213 if ((status & 0x4) == 0) { 2214 ssc->ses_objmap[oid].encstat[3] = 0x10; 2215 } 2216 ssc->ses_objmap[oid++].svalid = 1; 2217 } 2218 /* see comment below about sticky enclosure status */ 2219 ssc->ses_encstat |= ENCI_SVALID | oencstat; 2220 SES_FREE(sdata, buflen); 2221 return (0); 2222 } 2223 2224 static int 2225 set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp) 2226 { 2227 int idx; 2228 encobj *ep; 2229 struct scfg *cc = ssc->ses_private; 2230 2231 if (cc == NULL) 2232 return (0); 2233 2234 idx = (int)obp->obj_id; 2235 ep = &ssc->ses_objmap[idx]; 2236 2237 switch (ep->enctype) { 2238 case SESTYP_DEVICE: 2239 if (obp->cstat[0] & SESCTL_PRDFAIL) { 2240 ep->priv |= 0x40; 2241 } 2242 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */ 2243 if (obp->cstat[0] & SESCTL_DISABLE) { 2244 ep->priv |= 0x80; 2245 /* 2246 * Hmm. Try to set the 'No Drive' flag. 2247 * Maybe that will count as a 'disable'. 2248 */ 2249 } 2250 if (ep->priv & 0xc6) { 2251 ep->priv &= ~0x1; 2252 } else { 2253 ep->priv |= 0x1; /* no errors */ 2254 } 2255 wrslot_stat(ssc, slp); 2256 break; 2257 case SESTYP_POWER: 2258 /* 2259 * Okay- the only one that makes sense here is to 2260 * do the 'disable' for a power supply. 2261 */ 2262 if (obp->cstat[0] & SESCTL_DISABLE) { 2263 (void) wrbuf16(ssc, SAFTE_WT_ACTPWS, 2264 idx - cc->pwroff, 0, 0, slp); 2265 } 2266 break; 2267 case SESTYP_FAN: 2268 /* 2269 * Okay- the only one that makes sense here is to 2270 * set fan speed to zero on disable. 2271 */ 2272 if (obp->cstat[0] & SESCTL_DISABLE) { 2273 /* remember- fans are the first items, so idx works */ 2274 (void) wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 2275 } 2276 break; 2277 case SESTYP_DOORLOCK: 2278 /* 2279 * Well, we can 'disable' the lock. 2280 */ 2281 if (obp->cstat[0] & SESCTL_DISABLE) { 2282 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 2283 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2284 cc->flag2, 0, slp); 2285 } 2286 break; 2287 case SESTYP_ALARM: 2288 /* 2289 * Well, we can 'disable' the alarm. 2290 */ 2291 if (obp->cstat[0] & SESCTL_DISABLE) { 2292 cc->flag2 &= ~SAFT_FLG1_ALARM; 2293 ep->priv |= 0x40; /* Muted */ 2294 (void) wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2295 cc->flag2, 0, slp); 2296 } 2297 break; 2298 default: 2299 break; 2300 } 2301 ep->svalid = 0; 2302 return (0); 2303 } 2304 2305 /* 2306 * This function handles all of the 16 byte WRITE BUFFER commands. 2307 */ 2308 static int 2309 wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2, 2310 uint8_t b3, int slp) 2311 { 2312 int err, amt; 2313 char *sdata; 2314 struct scfg *cc = ssc->ses_private; 2315 static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 }; 2316 2317 if (cc == NULL) 2318 return (0); 2319 2320 sdata = SES_MALLOC(16); 2321 if (sdata == NULL) 2322 return (ENOMEM); 2323 2324 SES_VLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3); 2325 2326 sdata[0] = op; 2327 sdata[1] = b1; 2328 sdata[2] = b2; 2329 sdata[3] = b3; 2330 MEMZERO(&sdata[4], 12); 2331 amt = -16; 2332 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2333 SES_FREE(sdata, 16); 2334 return (err); 2335 } 2336 2337 /* 2338 * This function updates the status byte for the device slot described. 2339 * 2340 * Since this is an optional SAF-TE command, there's no point in 2341 * returning an error. 2342 */ 2343 static void 2344 wrslot_stat(ses_softc_t *ssc, int slp) 2345 { 2346 int i, amt; 2347 encobj *ep; 2348 char cdb[10], *sdata; 2349 struct scfg *cc = ssc->ses_private; 2350 2351 if (cc == NULL) 2352 return; 2353 2354 SES_VLOG(ssc, "saf_wrslot\n"); 2355 cdb[0] = WRITE_BUFFER; 2356 cdb[1] = 1; 2357 cdb[2] = 0; 2358 cdb[3] = 0; 2359 cdb[4] = 0; 2360 cdb[5] = 0; 2361 cdb[6] = 0; 2362 cdb[7] = 0; 2363 cdb[8] = cc->Nslots * 3 + 1; 2364 cdb[9] = 0; 2365 2366 sdata = SES_MALLOC(cc->Nslots * 3 + 1); 2367 if (sdata == NULL) 2368 return; 2369 MEMZERO(sdata, cc->Nslots * 3 + 1); 2370 2371 sdata[0] = SAFTE_WT_DSTAT; 2372 for (i = 0; i < cc->Nslots; i++) { 2373 ep = &ssc->ses_objmap[cc->slotoff + i]; 2374 SES_VLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff); 2375 sdata[1 + (3 * i)] = ep->priv & 0xff; 2376 } 2377 amt = -(cc->Nslots * 3 + 1); 2378 (void) ses_runcmd(ssc, cdb, 10, sdata, &amt); 2379 SES_FREE(sdata, cc->Nslots * 3 + 1); 2380 } 2381 2382 /* 2383 * This function issues the "PERFORM SLOT OPERATION" command. 2384 */ 2385 static int 2386 perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp) 2387 { 2388 int err, amt; 2389 char *sdata; 2390 struct scfg *cc = ssc->ses_private; 2391 static char cdb[10] = 2392 { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 2393 2394 if (cc == NULL) 2395 return (0); 2396 2397 sdata = SES_MALLOC(SAFT_SCRATCH); 2398 if (sdata == NULL) 2399 return (ENOMEM); 2400 MEMZERO(sdata, SAFT_SCRATCH); 2401 2402 sdata[0] = SAFTE_WT_SLTOP; 2403 sdata[1] = slot; 2404 sdata[2] = opflag; 2405 SES_VLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag); 2406 amt = -SAFT_SCRATCH; 2407 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2408 SES_FREE(sdata, SAFT_SCRATCH); 2409 return (err); 2410 } 2411