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