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