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