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