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