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