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