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