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