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