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