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 cc = ssc->ses_private; 1217 if (cc == NULL) { 1218 return (ENXIO); 1219 } 1220 1221 /* 1222 * If we're just getting overall enclosure status, 1223 * we only need 2 bytes of data storage. 1224 * 1225 * If we're getting anything else, we know how much 1226 * storage we need by noting that starting at offset 1227 * 8 in returned data, all object status bytes are 4 1228 * bytes long, and are stored in chunks of types(M) 1229 * and nth+1 instances of type M. 1230 */ 1231 if (objid == -1) { 1232 bufsiz = 2; 1233 } else { 1234 bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8; 1235 } 1236 sdata = SES_MALLOC(bufsiz); 1237 if (sdata == NULL) 1238 return (ENOMEM); 1239 1240 cdb[0] = RECEIVE_DIAGNOSTIC; 1241 cdb[1] = 1; 1242 cdb[2] = SesStatusPage; 1243 cdb[3] = bufsiz >> 8; 1244 cdb[4] = bufsiz & 0xff; 1245 cdb[5] = 0; 1246 amt = bufsiz; 1247 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1248 if (err) { 1249 SES_FREE(sdata, bufsiz); 1250 return (err); 1251 } 1252 amt = bufsiz - amt; 1253 1254 if (objid == -1) { 1255 tidx = -1; 1256 oidx = -1; 1257 } else { 1258 tidx = cc->ses_typidx[objid].ses_tidx; 1259 oidx = cc->ses_typidx[objid].ses_oidx; 1260 } 1261 if (in) { 1262 if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1263 err = ENODEV; 1264 } 1265 } else { 1266 if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1267 err = ENODEV; 1268 } else { 1269 cdb[0] = SEND_DIAGNOSTIC; 1270 cdb[1] = 0x10; 1271 cdb[2] = 0; 1272 cdb[3] = bufsiz >> 8; 1273 cdb[4] = bufsiz & 0xff; 1274 cdb[5] = 0; 1275 amt = -bufsiz; 1276 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1277 } 1278 } 1279 SES_FREE(sdata, bufsiz); 1280 return (0); 1281 } 1282 1283 1284 /* 1285 * Routines to parse returned SES data structures. 1286 * Architecture and compiler independent. 1287 */ 1288 1289 static int 1290 ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp) 1291 { 1292 if (buflen < SES_CFGHDR_MINLEN) { 1293 return (-1); 1294 } 1295 gget8(buffer, 1, cfp->Nsubenc); 1296 gget32(buffer, 4, cfp->GenCode); 1297 return (0); 1298 } 1299 1300 static int 1301 ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp) 1302 { 1303 int s, off = 8; 1304 for (s = 0; s < SubEncId; s++) { 1305 if (off + 3 > amt) 1306 return (-1); 1307 off += buffer[off+3] + 4; 1308 } 1309 if (off + 3 > amt) { 1310 return (-1); 1311 } 1312 gget8(buffer, off+1, chp->Subencid); 1313 gget8(buffer, off+2, chp->Ntypes); 1314 gget8(buffer, off+3, chp->VEnclen); 1315 return (0); 1316 } 1317 1318 static int 1319 ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp) 1320 { 1321 int s, e, enclen, off = 8; 1322 for (s = 0; s < SubEncId; s++) { 1323 if (off + 3 > amt) 1324 return (-1); 1325 off += buffer[off+3] + 4; 1326 } 1327 if (off + 3 > amt) { 1328 return (-1); 1329 } 1330 gget8(buffer, off+3, enclen); 1331 off += 4; 1332 if (off >= amt) 1333 return (-1); 1334 1335 e = off + enclen; 1336 if (e > amt) { 1337 e = amt; 1338 } 1339 MEMCPY(cdp, &buffer[off], e - off); 1340 return (0); 1341 } 1342 1343 static int 1344 ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp) 1345 { 1346 int s, off = 8; 1347 1348 if (amt < SES_CFGHDR_MINLEN) { 1349 return (-1); 1350 } 1351 for (s = 0; s < buffer[1]; s++) { 1352 if (off + 3 > amt) 1353 return (-1); 1354 off += buffer[off+3] + 4; 1355 } 1356 if (off + 3 > amt) { 1357 return (-1); 1358 } 1359 off += buffer[off+3] + 4 + (nth * 4); 1360 if (amt < (off + 4)) 1361 return (-1); 1362 1363 gget8(buffer, off++, thp->enc_type); 1364 gget8(buffer, off++, thp->enc_maxelt); 1365 gget8(buffer, off++, thp->enc_subenc); 1366 gget8(buffer, off, thp->enc_tlen); 1367 return (0); 1368 } 1369 1370 /* 1371 * This function needs a little explanation. 1372 * 1373 * The arguments are: 1374 * 1375 * 1376 * char *b, int amt 1377 * 1378 * These describes the raw input SES status data and length. 1379 * 1380 * uint8_t *ep 1381 * 1382 * This is a map of the number of types for each element type 1383 * in the enclosure. 1384 * 1385 * int elt 1386 * 1387 * This is the element type being sought. If elt is -1, 1388 * then overall enclosure status is being sought. 1389 * 1390 * int elm 1391 * 1392 * This is the ordinal Mth element of type elt being sought. 1393 * 1394 * SesComStat *sp 1395 * 1396 * This is the output area to store the status for 1397 * the Mth element of type Elt. 1398 */ 1399 1400 static int 1401 ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1402 { 1403 int idx, i; 1404 1405 /* 1406 * If it's overall enclosure status being sought, get that. 1407 * We need at least 2 bytes of status data to get that. 1408 */ 1409 if (elt == -1) { 1410 if (amt < 2) 1411 return (-1); 1412 gget8(b, 1, sp->comstatus); 1413 sp->comstat[0] = 0; 1414 sp->comstat[1] = 0; 1415 sp->comstat[2] = 0; 1416 return (0); 1417 } 1418 1419 /* 1420 * Check to make sure that the Mth element is legal for type Elt. 1421 */ 1422 1423 if (elm >= ep[elt]) 1424 return (-1); 1425 1426 /* 1427 * Starting at offset 8, start skipping over the storage 1428 * for the element types we're not interested in. 1429 */ 1430 for (idx = 8, i = 0; i < elt; i++) { 1431 idx += ((ep[i] + 1) * 4); 1432 } 1433 1434 /* 1435 * Skip over Overall status for this element type. 1436 */ 1437 idx += 4; 1438 1439 /* 1440 * And skip to the index for the Mth element that we're going for. 1441 */ 1442 idx += (4 * elm); 1443 1444 /* 1445 * Make sure we haven't overflowed the buffer. 1446 */ 1447 if (idx+4 > amt) 1448 return (-1); 1449 1450 /* 1451 * Retrieve the status. 1452 */ 1453 gget8(b, idx++, sp->comstatus); 1454 gget8(b, idx++, sp->comstat[0]); 1455 gget8(b, idx++, sp->comstat[1]); 1456 gget8(b, idx++, sp->comstat[2]); 1457 #if 0 1458 PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4); 1459 #endif 1460 return (0); 1461 } 1462 1463 /* 1464 * This is the mirror function to ses_decode, but we set the 'select' 1465 * bit for the object which we're interested in. All other objects, 1466 * after a status fetch, should have that bit off. Hmm. It'd be easy 1467 * enough to ensure this, so we will. 1468 */ 1469 1470 static int 1471 ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1472 { 1473 int idx, i; 1474 1475 /* 1476 * If it's overall enclosure status being sought, get that. 1477 * We need at least 2 bytes of status data to get that. 1478 */ 1479 if (elt == -1) { 1480 if (amt < 2) 1481 return (-1); 1482 i = 0; 1483 sset8(b, i, 0); 1484 sset8(b, i, sp->comstatus & 0xf); 1485 #if 0 1486 PRINTF("set EncStat %x\n", sp->comstatus); 1487 #endif 1488 return (0); 1489 } 1490 1491 /* 1492 * Check to make sure that the Mth element is legal for type Elt. 1493 */ 1494 1495 if (elm >= ep[elt]) 1496 return (-1); 1497 1498 /* 1499 * Starting at offset 8, start skipping over the storage 1500 * for the element types we're not interested in. 1501 */ 1502 for (idx = 8, i = 0; i < elt; i++) { 1503 idx += ((ep[i] + 1) * 4); 1504 } 1505 1506 /* 1507 * Skip over Overall status for this element type. 1508 */ 1509 idx += 4; 1510 1511 /* 1512 * And skip to the index for the Mth element that we're going for. 1513 */ 1514 idx += (4 * elm); 1515 1516 /* 1517 * Make sure we haven't overflowed the buffer. 1518 */ 1519 if (idx+4 > amt) 1520 return (-1); 1521 1522 /* 1523 * Set the status. 1524 */ 1525 sset8(b, idx, sp->comstatus); 1526 sset8(b, idx, sp->comstat[0]); 1527 sset8(b, idx, sp->comstat[1]); 1528 sset8(b, idx, sp->comstat[2]); 1529 idx -= 4; 1530 1531 #if 0 1532 PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n", 1533 elt, elm, idx, sp->comstatus, sp->comstat[0], 1534 sp->comstat[1], sp->comstat[2]); 1535 #endif 1536 1537 /* 1538 * Now make sure all other 'Select' bits are off. 1539 */ 1540 for (i = 8; i < amt; i += 4) { 1541 if (i != idx) 1542 b[i] &= ~0x80; 1543 } 1544 /* 1545 * And make sure the INVOP bit is clear. 1546 */ 1547 b[2] &= ~0x10; 1548 1549 return (0); 1550 } 1551 1552 /* 1553 * SAF-TE Type Device Emulation 1554 */ 1555 1556 static int safte_getconfig(ses_softc_t *); 1557 static int safte_rdstat(ses_softc_t *, int); 1558 static int set_objstat_sel(ses_softc_t *, ses_objstat *, int); 1559 static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int); 1560 static void wrslot_stat(ses_softc_t *, int); 1561 static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int); 1562 1563 #define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \ 1564 SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) 1565 /* 1566 * SAF-TE specific defines- Mandatory ones only... 1567 */ 1568 1569 /* 1570 * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb 1571 */ 1572 #define SAFTE_RD_RDCFG 0x00 /* read enclosure configuration */ 1573 #define SAFTE_RD_RDESTS 0x01 /* read enclosure status */ 1574 #define SAFTE_RD_RDDSTS 0x04 /* read drive slot status */ 1575 1576 /* 1577 * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf 1578 */ 1579 #define SAFTE_WT_DSTAT 0x10 /* write device slot status */ 1580 #define SAFTE_WT_SLTOP 0x12 /* perform slot operation */ 1581 #define SAFTE_WT_FANSPD 0x13 /* set fan speed */ 1582 #define SAFTE_WT_ACTPWS 0x14 /* turn on/off power supply */ 1583 #define SAFTE_WT_GLOBAL 0x15 /* send global command */ 1584 1585 1586 #define SAFT_SCRATCH 64 1587 #define NPSEUDO_THERM 16 1588 #define NPSEUDO_ALARM 1 1589 struct scfg { 1590 /* 1591 * Cached Configuration 1592 */ 1593 uint8_t Nfans; /* Number of Fans */ 1594 uint8_t Npwr; /* Number of Power Supplies */ 1595 uint8_t Nslots; /* Number of Device Slots */ 1596 uint8_t DoorLock; /* Door Lock Installed */ 1597 uint8_t Ntherm; /* Number of Temperature Sensors */ 1598 uint8_t Nspkrs; /* Number of Speakers */ 1599 uint8_t Nalarm; /* Number of Alarms (at least one) */ 1600 /* 1601 * Cached Flag Bytes for Global Status 1602 */ 1603 uint8_t flag1; 1604 uint8_t flag2; 1605 /* 1606 * What object index ID is where various slots start. 1607 */ 1608 uint8_t pwroff; 1609 uint8_t slotoff; 1610 #define SAFT_ALARM_OFFSET(cc) (cc)->slotoff - 1 1611 }; 1612 1613 #define SAFT_FLG1_ALARM 0x1 1614 #define SAFT_FLG1_GLOBFAIL 0x2 1615 #define SAFT_FLG1_GLOBWARN 0x4 1616 #define SAFT_FLG1_ENCPWROFF 0x8 1617 #define SAFT_FLG1_ENCFANFAIL 0x10 1618 #define SAFT_FLG1_ENCPWRFAIL 0x20 1619 #define SAFT_FLG1_ENCDRVFAIL 0x40 1620 #define SAFT_FLG1_ENCDRVWARN 0x80 1621 1622 #define SAFT_FLG2_LOCKDOOR 0x4 1623 #define SAFT_PRIVATE sizeof (struct scfg) 1624 1625 static char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; 1626 #define SAFT_BAIL(r, x, k, l) \ 1627 if ((r) >= (x)) { \ 1628 SES_LOG(ssc, safte_2little, x, __LINE__);\ 1629 SES_FREE((k), (l)); \ 1630 return (EIO); \ 1631 } 1632 1633 1634 static int 1635 safte_softc_init(ses_softc_t *ssc, int doinit) 1636 { 1637 int err, i, r; 1638 struct scfg *cc; 1639 1640 if (doinit == 0) { 1641 if (ssc->ses_nobjects) { 1642 if (ssc->ses_objmap) { 1643 SES_FREE(ssc->ses_objmap, 1644 ssc->ses_nobjects * sizeof (encobj)); 1645 ssc->ses_objmap = NULL; 1646 } 1647 ssc->ses_nobjects = 0; 1648 } 1649 if (ssc->ses_private) { 1650 SES_FREE(ssc->ses_private, SAFT_PRIVATE); 1651 ssc->ses_private = NULL; 1652 } 1653 return (0); 1654 } 1655 1656 if (ssc->ses_private == NULL) { 1657 ssc->ses_private = SES_MALLOC(SAFT_PRIVATE); 1658 if (ssc->ses_private == NULL) { 1659 return (ENOMEM); 1660 } 1661 MEMZERO(ssc->ses_private, SAFT_PRIVATE); 1662 } 1663 1664 ssc->ses_nobjects = 0; 1665 ssc->ses_encstat = 0; 1666 1667 if ((err = safte_getconfig(ssc)) != 0) { 1668 return (err); 1669 } 1670 1671 /* 1672 * The number of objects here, as well as that reported by the 1673 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15) 1674 * that get reported during READ_BUFFER/READ_ENC_STATUS. 1675 */ 1676 cc = ssc->ses_private; 1677 ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock + 1678 cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM; 1679 ssc->ses_objmap = (encobj *) 1680 SES_MALLOC(ssc->ses_nobjects * sizeof (encobj)); 1681 if (ssc->ses_objmap == NULL) { 1682 return (ENOMEM); 1683 } 1684 MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj)); 1685 1686 r = 0; 1687 /* 1688 * Note that this is all arranged for the convenience 1689 * in later fetches of status. 1690 */ 1691 for (i = 0; i < cc->Nfans; i++) 1692 ssc->ses_objmap[r++].enctype = SESTYP_FAN; 1693 cc->pwroff = (uint8_t) r; 1694 for (i = 0; i < cc->Npwr; i++) 1695 ssc->ses_objmap[r++].enctype = SESTYP_POWER; 1696 for (i = 0; i < cc->DoorLock; i++) 1697 ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK; 1698 for (i = 0; i < cc->Nspkrs; i++) 1699 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1700 for (i = 0; i < cc->Ntherm; i++) 1701 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1702 for (i = 0; i < NPSEUDO_THERM; i++) 1703 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1704 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1705 cc->slotoff = (uint8_t) r; 1706 for (i = 0; i < cc->Nslots; i++) 1707 ssc->ses_objmap[r++].enctype = SESTYP_DEVICE; 1708 return (0); 1709 } 1710 1711 static int 1712 safte_init_enc(ses_softc_t *ssc) 1713 { 1714 int err; 1715 static char cdb0[6] = { SEND_DIAGNOSTIC }; 1716 1717 err = ses_runcmd(ssc, cdb0, 6, NULL, 0); 1718 if (err) { 1719 return (err); 1720 } 1721 DELAY(5000); 1722 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, 0, 0, 0, 1); 1723 return (err); 1724 } 1725 1726 static int 1727 safte_get_encstat(ses_softc_t *ssc, int slpflg) 1728 { 1729 return (safte_rdstat(ssc, slpflg)); 1730 } 1731 1732 static int 1733 safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg) 1734 { 1735 struct scfg *cc = ssc->ses_private; 1736 if (cc == NULL) 1737 return (0); 1738 /* 1739 * Since SAF-TE devices aren't necessarily sticky in terms 1740 * of state, make our soft copy of enclosure status 'sticky'- 1741 * that is, things set in enclosure status stay set (as implied 1742 * by conditions set in reading object status) until cleared. 1743 */ 1744 ssc->ses_encstat &= ~ALL_ENC_STAT; 1745 ssc->ses_encstat |= (encstat & ALL_ENC_STAT); 1746 ssc->ses_encstat |= ENCI_SVALID; 1747 cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN); 1748 if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) { 1749 cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL; 1750 } else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) { 1751 cc->flag1 |= SAFT_FLG1_GLOBWARN; 1752 } 1753 return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg)); 1754 } 1755 1756 static int 1757 safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg) 1758 { 1759 int i = (int)obp->obj_id; 1760 1761 if ((ssc->ses_encstat & ENCI_SVALID) == 0 || 1762 (ssc->ses_objmap[i].svalid) == 0) { 1763 int err = safte_rdstat(ssc, slpflg); 1764 if (err) 1765 return (err); 1766 } 1767 obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; 1768 obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; 1769 obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; 1770 obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; 1771 return (0); 1772 } 1773 1774 1775 static int 1776 safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp) 1777 { 1778 int idx, err; 1779 encobj *ep; 1780 struct scfg *cc; 1781 1782 1783 SES_DLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n", 1784 (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2], 1785 obp->cstat[3]); 1786 1787 /* 1788 * If this is clear, we don't do diddly. 1789 */ 1790 if ((obp->cstat[0] & SESCTL_CSEL) == 0) { 1791 return (0); 1792 } 1793 1794 err = 0; 1795 /* 1796 * Check to see if the common bits are set and do them first. 1797 */ 1798 if (obp->cstat[0] & ~SESCTL_CSEL) { 1799 err = set_objstat_sel(ssc, obp, slp); 1800 if (err) 1801 return (err); 1802 } 1803 1804 cc = ssc->ses_private; 1805 if (cc == NULL) 1806 return (0); 1807 1808 idx = (int)obp->obj_id; 1809 ep = &ssc->ses_objmap[idx]; 1810 1811 switch (ep->enctype) { 1812 case SESTYP_DEVICE: 1813 { 1814 uint8_t slotop = 0; 1815 /* 1816 * XXX: I should probably cache the previous state 1817 * XXX: of SESCTL_DEVOFF so that when it goes from 1818 * XXX: true to false I can then set PREPARE FOR OPERATION 1819 * XXX: flag in PERFORM SLOT OPERATION write buffer command. 1820 */ 1821 if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) { 1822 slotop |= 0x2; 1823 } 1824 if (obp->cstat[2] & SESCTL_RQSID) { 1825 slotop |= 0x4; 1826 } 1827 err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff, 1828 slotop, slp); 1829 if (err) 1830 return (err); 1831 if (obp->cstat[3] & SESCTL_RQSFLT) { 1832 ep->priv |= 0x2; 1833 } else { 1834 ep->priv &= ~0x2; 1835 } 1836 if (ep->priv & 0xc6) { 1837 ep->priv &= ~0x1; 1838 } else { 1839 ep->priv |= 0x1; /* no errors */ 1840 } 1841 wrslot_stat(ssc, slp); 1842 break; 1843 } 1844 case SESTYP_POWER: 1845 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1846 cc->flag1 |= SAFT_FLG1_ENCPWRFAIL; 1847 } else { 1848 cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL; 1849 } 1850 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1851 cc->flag2, 0, slp); 1852 if (err) 1853 return (err); 1854 if (obp->cstat[3] & SESCTL_RQSTON) { 1855 wrbuf16(ssc, SAFTE_WT_ACTPWS, 1856 idx - cc->pwroff, 0, 0, slp); 1857 } else { 1858 wrbuf16(ssc, SAFTE_WT_ACTPWS, 1859 idx - cc->pwroff, 0, 1, slp); 1860 } 1861 break; 1862 case SESTYP_FAN: 1863 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1864 cc->flag1 |= SAFT_FLG1_ENCFANFAIL; 1865 } else { 1866 cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL; 1867 } 1868 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1869 cc->flag2, 0, slp); 1870 if (err) 1871 return (err); 1872 if (obp->cstat[3] & SESCTL_RQSTON) { 1873 uint8_t fsp; 1874 if ((obp->cstat[3] & 0x7) == 7) { 1875 fsp = 4; 1876 } else if ((obp->cstat[3] & 0x7) == 6) { 1877 fsp = 3; 1878 } else if ((obp->cstat[3] & 0x7) == 4) { 1879 fsp = 2; 1880 } else { 1881 fsp = 1; 1882 } 1883 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp); 1884 } else { 1885 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 1886 } 1887 break; 1888 case SESTYP_DOORLOCK: 1889 if (obp->cstat[3] & 0x1) { 1890 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 1891 } else { 1892 cc->flag2 |= SAFT_FLG2_LOCKDOOR; 1893 } 1894 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slp); 1895 break; 1896 case SESTYP_ALARM: 1897 /* 1898 * On all nonzero but the 'muted' bit, we turn on the alarm, 1899 */ 1900 obp->cstat[3] &= ~0xa; 1901 if (obp->cstat[3] & 0x40) { 1902 cc->flag2 &= ~SAFT_FLG1_ALARM; 1903 } else if (obp->cstat[3] != 0) { 1904 cc->flag2 |= SAFT_FLG1_ALARM; 1905 } else { 1906 cc->flag2 &= ~SAFT_FLG1_ALARM; 1907 } 1908 ep->priv = obp->cstat[3]; 1909 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slp); 1910 break; 1911 default: 1912 break; 1913 } 1914 ep->svalid = 0; 1915 return (0); 1916 } 1917 1918 static int 1919 safte_getconfig(ses_softc_t *ssc) 1920 { 1921 struct scfg *cfg; 1922 int err, amt; 1923 char *sdata; 1924 static char cdb[10] = 1925 { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 1926 1927 cfg = ssc->ses_private; 1928 if (cfg == NULL) 1929 return (ENXIO); 1930 1931 sdata = SES_MALLOC(SAFT_SCRATCH); 1932 if (sdata == NULL) 1933 return (ENOMEM); 1934 1935 amt = SAFT_SCRATCH; 1936 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1937 if (err) { 1938 SES_FREE(sdata, SAFT_SCRATCH); 1939 return (err); 1940 } 1941 amt = SAFT_SCRATCH - amt; 1942 if (amt < 6) { 1943 SES_LOG(ssc, "too little data (%d) for configuration\n", amt); 1944 SES_FREE(sdata, SAFT_SCRATCH); 1945 return (EIO); 1946 } 1947 SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n", 1948 sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); 1949 cfg->Nfans = sdata[0]; 1950 cfg->Npwr = sdata[1]; 1951 cfg->Nslots = sdata[2]; 1952 cfg->DoorLock = sdata[3]; 1953 cfg->Ntherm = sdata[4]; 1954 cfg->Nspkrs = sdata[5]; 1955 cfg->Nalarm = NPSEUDO_ALARM; 1956 SES_FREE(sdata, SAFT_SCRATCH); 1957 return (0); 1958 } 1959 1960 static int 1961 safte_rdstat(ses_softc_t *ssc, int slpflg) 1962 { 1963 int err, oid, r, i, hiwater, nitems, amt; 1964 uint16_t tempflags; 1965 size_t buflen; 1966 uint8_t status, oencstat; 1967 char *sdata, cdb[10]; 1968 struct scfg *cc = ssc->ses_private; 1969 1970 1971 /* 1972 * The number of objects overstates things a bit, 1973 * both for the bogus 'thermometer' entries and 1974 * the drive status (which isn't read at the same 1975 * time as the enclosure status), but that's okay. 1976 */ 1977 buflen = 4 * cc->Nslots; 1978 if (ssc->ses_nobjects > buflen) 1979 buflen = ssc->ses_nobjects; 1980 sdata = SES_MALLOC(buflen); 1981 if (sdata == NULL) 1982 return (ENOMEM); 1983 1984 cdb[0] = READ_BUFFER; 1985 cdb[1] = 1; 1986 cdb[2] = SAFTE_RD_RDESTS; 1987 cdb[3] = 0; 1988 cdb[4] = 0; 1989 cdb[5] = 0; 1990 cdb[6] = 0; 1991 cdb[7] = (buflen >> 8) & 0xff; 1992 cdb[8] = buflen & 0xff; 1993 cdb[9] = 0; 1994 amt = buflen; 1995 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1996 if (err) { 1997 SES_FREE(sdata, buflen); 1998 return (err); 1999 } 2000 hiwater = buflen - amt; 2001 2002 2003 /* 2004 * invalidate all status bits. 2005 */ 2006 for (i = 0; i < ssc->ses_nobjects; i++) 2007 ssc->ses_objmap[i].svalid = 0; 2008 oencstat = ssc->ses_encstat & ALL_ENC_STAT; 2009 ssc->ses_encstat = 0; 2010 2011 2012 /* 2013 * Now parse returned buffer. 2014 * If we didn't get enough data back, 2015 * that's considered a fatal error. 2016 */ 2017 oid = r = 0; 2018 2019 for (nitems = i = 0; i < cc->Nfans; i++) { 2020 SAFT_BAIL(r, hiwater, sdata, buflen); 2021 /* 2022 * 0 = Fan Operational 2023 * 1 = Fan is malfunctioning 2024 * 2 = Fan is not present 2025 * 0x80 = Unknown or Not Reportable Status 2026 */ 2027 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 2028 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 2029 switch ((int)(uint8_t)sdata[r]) { 2030 case 0: 2031 nitems++; 2032 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2033 /* 2034 * We could get fancier and cache 2035 * fan speeds that we have set, but 2036 * that isn't done now. 2037 */ 2038 ssc->ses_objmap[oid].encstat[3] = 7; 2039 break; 2040 2041 case 1: 2042 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2043 /* 2044 * FAIL and FAN STOPPED synthesized 2045 */ 2046 ssc->ses_objmap[oid].encstat[3] = 0x40; 2047 /* 2048 * Enclosure marked with CRITICAL error 2049 * if only one fan or no thermometers, 2050 * else the NONCRITICAL error is set. 2051 */ 2052 if (cc->Nfans == 1 || cc->Ntherm == 0) 2053 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2054 else 2055 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2056 break; 2057 case 2: 2058 ssc->ses_objmap[oid].encstat[0] = 2059 SES_OBJSTAT_NOTINSTALLED; 2060 ssc->ses_objmap[oid].encstat[3] = 0; 2061 /* 2062 * Enclosure marked with CRITICAL error 2063 * if only one fan or no thermometers, 2064 * else the NONCRITICAL error is set. 2065 */ 2066 if (cc->Nfans == 1) 2067 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2068 else 2069 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2070 break; 2071 case 0x80: 2072 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2073 ssc->ses_objmap[oid].encstat[3] = 0; 2074 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2075 break; 2076 default: 2077 ssc->ses_objmap[oid].encstat[0] = 2078 SES_OBJSTAT_UNSUPPORTED; 2079 SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i, 2080 sdata[r] & 0xff); 2081 break; 2082 } 2083 ssc->ses_objmap[oid++].svalid = 1; 2084 r++; 2085 } 2086 2087 /* 2088 * No matter how you cut it, no cooling elements when there 2089 * should be some there is critical. 2090 */ 2091 if (cc->Nfans && nitems == 0) { 2092 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2093 } 2094 2095 2096 for (i = 0; i < cc->Npwr; i++) { 2097 SAFT_BAIL(r, hiwater, sdata, buflen); 2098 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2099 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 2100 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 2101 ssc->ses_objmap[oid].encstat[3] = 0x20; /* requested on */ 2102 switch ((uint8_t)sdata[r]) { 2103 case 0x00: /* pws operational and on */ 2104 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2105 break; 2106 case 0x01: /* pws operational and off */ 2107 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2108 ssc->ses_objmap[oid].encstat[3] = 0x10; 2109 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2110 break; 2111 case 0x10: /* pws is malfunctioning and commanded on */ 2112 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2113 ssc->ses_objmap[oid].encstat[3] = 0x61; 2114 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2115 break; 2116 2117 case 0x11: /* pws is malfunctioning and commanded off */ 2118 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 2119 ssc->ses_objmap[oid].encstat[3] = 0x51; 2120 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2121 break; 2122 case 0x20: /* pws is not present */ 2123 ssc->ses_objmap[oid].encstat[0] = 2124 SES_OBJSTAT_NOTINSTALLED; 2125 ssc->ses_objmap[oid].encstat[3] = 0; 2126 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2127 break; 2128 case 0x21: /* pws is present */ 2129 /* 2130 * This is for enclosures that cannot tell whether the 2131 * device is on or malfunctioning, but know that it is 2132 * present. Just fall through. 2133 */ 2134 /* FALLTHROUGH */ 2135 case 0x80: /* Unknown or Not Reportable Status */ 2136 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2137 ssc->ses_objmap[oid].encstat[3] = 0; 2138 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2139 break; 2140 default: 2141 SES_LOG(ssc, "unknown power supply %d status (0x%x)\n", 2142 i, sdata[r] & 0xff); 2143 break; 2144 } 2145 ssc->ses_objmap[oid++].svalid = 1; 2146 r++; 2147 } 2148 2149 /* 2150 * Skip over Slot SCSI IDs 2151 */ 2152 r += cc->Nslots; 2153 2154 /* 2155 * We always have doorlock status, no matter what, 2156 * but we only save the status if we have one. 2157 */ 2158 SAFT_BAIL(r, hiwater, sdata, buflen); 2159 if (cc->DoorLock) { 2160 /* 2161 * 0 = Door Locked 2162 * 1 = Door Unlocked, or no Lock Installed 2163 * 0x80 = Unknown or Not Reportable Status 2164 */ 2165 ssc->ses_objmap[oid].encstat[1] = 0; 2166 ssc->ses_objmap[oid].encstat[2] = 0; 2167 switch ((uint8_t)sdata[r]) { 2168 case 0: 2169 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2170 ssc->ses_objmap[oid].encstat[3] = 0; 2171 break; 2172 case 1: 2173 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2174 ssc->ses_objmap[oid].encstat[3] = 1; 2175 break; 2176 case 0x80: 2177 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2178 ssc->ses_objmap[oid].encstat[3] = 0; 2179 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2180 break; 2181 default: 2182 ssc->ses_objmap[oid].encstat[0] = 2183 SES_OBJSTAT_UNSUPPORTED; 2184 SES_LOG(ssc, "unknown lock status 0x%x\n", 2185 sdata[r] & 0xff); 2186 break; 2187 } 2188 ssc->ses_objmap[oid++].svalid = 1; 2189 } 2190 r++; 2191 2192 /* 2193 * We always have speaker status, no matter what, 2194 * but we only save the status if we have one. 2195 */ 2196 SAFT_BAIL(r, hiwater, sdata, buflen); 2197 if (cc->Nspkrs) { 2198 ssc->ses_objmap[oid].encstat[1] = 0; 2199 ssc->ses_objmap[oid].encstat[2] = 0; 2200 if (sdata[r] == 1) { 2201 /* 2202 * We need to cache tone urgency indicators. 2203 * Someday. 2204 */ 2205 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 2206 ssc->ses_objmap[oid].encstat[3] = 0x8; 2207 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2208 } else if (sdata[r] == 0) { 2209 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2210 ssc->ses_objmap[oid].encstat[3] = 0; 2211 } else { 2212 ssc->ses_objmap[oid].encstat[0] = 2213 SES_OBJSTAT_UNSUPPORTED; 2214 ssc->ses_objmap[oid].encstat[3] = 0; 2215 SES_LOG(ssc, "unknown spkr status 0x%x\n", 2216 sdata[r] & 0xff); 2217 } 2218 ssc->ses_objmap[oid++].svalid = 1; 2219 } 2220 r++; 2221 2222 for (i = 0; i < cc->Ntherm; i++) { 2223 SAFT_BAIL(r, hiwater, sdata, buflen); 2224 /* 2225 * Status is a range from -10 to 245 deg Celsius, 2226 * which we need to normalize to -20 to -245 according 2227 * to the latest SCSI spec, which makes little 2228 * sense since this would overflow an 8bit value. 2229 * Well, still, the base normalization is -20, 2230 * not -10, so we have to adjust. 2231 * 2232 * So what's over and under temperature? 2233 * Hmm- we'll state that 'normal' operating 2234 * is 10 to 40 deg Celsius. 2235 */ 2236 2237 /* 2238 * Actually.... All of the units that people out in the world 2239 * seem to have do not come even close to setting a value that 2240 * complies with this spec. 2241 * 2242 * The closest explanation I could find was in an 2243 * LSI-Logic manual, which seemed to indicate that 2244 * this value would be set by whatever the I2C code 2245 * would interpolate from the output of an LM75 2246 * temperature sensor. 2247 * 2248 * This means that it is impossible to use the actual 2249 * numeric value to predict anything. But we don't want 2250 * to lose the value. So, we'll propagate the *uncorrected* 2251 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the 2252 * temperature flags for warnings. 2253 */ 2254 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL; 2255 ssc->ses_objmap[oid].encstat[1] = 0; 2256 ssc->ses_objmap[oid].encstat[2] = sdata[r]; 2257 ssc->ses_objmap[oid].encstat[3] = 0; 2258 ssc->ses_objmap[oid++].svalid = 1; 2259 r++; 2260 } 2261 2262 /* 2263 * Now, for "pseudo" thermometers, we have two bytes 2264 * of information in enclosure status- 16 bits. Actually, 2265 * the MSB is a single TEMP ALERT flag indicating whether 2266 * any other bits are set, but, thanks to fuzzy thinking, 2267 * in the SAF-TE spec, this can also be set even if no 2268 * other bits are set, thus making this really another 2269 * binary temperature sensor. 2270 */ 2271 2272 SAFT_BAIL(r, hiwater, sdata, buflen); 2273 tempflags = sdata[r++]; 2274 SAFT_BAIL(r, hiwater, sdata, buflen); 2275 tempflags |= (tempflags << 8) | sdata[r++]; 2276 2277 for (i = 0; i < NPSEUDO_THERM; i++) { 2278 ssc->ses_objmap[oid].encstat[1] = 0; 2279 if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) { 2280 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2281 ssc->ses_objmap[4].encstat[2] = 0xff; 2282 /* 2283 * Set 'over temperature' failure. 2284 */ 2285 ssc->ses_objmap[oid].encstat[3] = 8; 2286 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2287 } else { 2288 /* 2289 * We used to say 'not available' and synthesize a 2290 * nominal 30 deg (C)- that was wrong. Actually, 2291 * Just say 'OK', and use the reserved value of 2292 * zero. 2293 */ 2294 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2295 ssc->ses_objmap[oid].encstat[2] = 0; 2296 ssc->ses_objmap[oid].encstat[3] = 0; 2297 } 2298 ssc->ses_objmap[oid++].svalid = 1; 2299 } 2300 2301 /* 2302 * Get alarm status. 2303 */ 2304 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2305 ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv; 2306 ssc->ses_objmap[oid++].svalid = 1; 2307 2308 /* 2309 * Now get drive slot status 2310 */ 2311 cdb[2] = SAFTE_RD_RDDSTS; 2312 amt = buflen; 2313 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2314 if (err) { 2315 SES_FREE(sdata, buflen); 2316 return (err); 2317 } 2318 hiwater = buflen - amt; 2319 for (r = i = 0; i < cc->Nslots; i++, r += 4) { 2320 SAFT_BAIL(r+3, hiwater, sdata, buflen); 2321 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED; 2322 ssc->ses_objmap[oid].encstat[1] = (uint8_t) i; 2323 ssc->ses_objmap[oid].encstat[2] = 0; 2324 ssc->ses_objmap[oid].encstat[3] = 0; 2325 status = sdata[r+3]; 2326 if ((status & 0x1) == 0) { /* no device */ 2327 ssc->ses_objmap[oid].encstat[0] = 2328 SES_OBJSTAT_NOTINSTALLED; 2329 } else { 2330 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2331 } 2332 if (status & 0x2) { 2333 ssc->ses_objmap[oid].encstat[2] = 0x8; 2334 } 2335 if ((status & 0x4) == 0) { 2336 ssc->ses_objmap[oid].encstat[3] = 0x10; 2337 } 2338 ssc->ses_objmap[oid++].svalid = 1; 2339 } 2340 /* see comment below about sticky enclosure status */ 2341 ssc->ses_encstat |= ENCI_SVALID | oencstat; 2342 SES_FREE(sdata, buflen); 2343 return (0); 2344 } 2345 2346 static int 2347 set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp) 2348 { 2349 int idx; 2350 encobj *ep; 2351 struct scfg *cc = ssc->ses_private; 2352 2353 if (cc == NULL) 2354 return (0); 2355 2356 idx = (int)obp->obj_id; 2357 ep = &ssc->ses_objmap[idx]; 2358 2359 switch (ep->enctype) { 2360 case SESTYP_DEVICE: 2361 if (obp->cstat[0] & SESCTL_PRDFAIL) { 2362 ep->priv |= 0x40; 2363 } 2364 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */ 2365 if (obp->cstat[0] & SESCTL_DISABLE) { 2366 ep->priv |= 0x80; 2367 /* 2368 * Hmm. Try to set the 'No Drive' flag. 2369 * Maybe that will count as a 'disable'. 2370 */ 2371 } 2372 if (ep->priv & 0xc6) { 2373 ep->priv &= ~0x1; 2374 } else { 2375 ep->priv |= 0x1; /* no errors */ 2376 } 2377 wrslot_stat(ssc, slp); 2378 break; 2379 case SESTYP_POWER: 2380 /* 2381 * Okay- the only one that makes sense here is to 2382 * do the 'disable' for a power supply. 2383 */ 2384 if (obp->cstat[0] & SESCTL_DISABLE) { 2385 wrbuf16(ssc, SAFTE_WT_ACTPWS, 2386 idx - cc->pwroff, 0, 0, slp); 2387 } 2388 break; 2389 case SESTYP_FAN: 2390 /* 2391 * Okay- the only one that makes sense here is to 2392 * set fan speed to zero on disable. 2393 */ 2394 if (obp->cstat[0] & SESCTL_DISABLE) { 2395 /* remember- fans are the first items, so idx works */ 2396 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 2397 } 2398 break; 2399 case SESTYP_DOORLOCK: 2400 /* 2401 * Well, we can 'disable' the lock. 2402 */ 2403 if (obp->cstat[0] & SESCTL_DISABLE) { 2404 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 2405 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2406 cc->flag2, 0, slp); 2407 } 2408 break; 2409 case SESTYP_ALARM: 2410 /* 2411 * Well, we can 'disable' the alarm. 2412 */ 2413 if (obp->cstat[0] & SESCTL_DISABLE) { 2414 cc->flag2 &= ~SAFT_FLG1_ALARM; 2415 ep->priv |= 0x40; /* Muted */ 2416 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2417 cc->flag2, 0, slp); 2418 } 2419 break; 2420 default: 2421 break; 2422 } 2423 ep->svalid = 0; 2424 return (0); 2425 } 2426 2427 /* 2428 * This function handles all of the 16 byte WRITE BUFFER commands. 2429 */ 2430 static int 2431 wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2, 2432 uint8_t b3, int slp) 2433 { 2434 int err, amt; 2435 char *sdata; 2436 struct scfg *cc = ssc->ses_private; 2437 static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 }; 2438 2439 if (cc == NULL) 2440 return (0); 2441 2442 sdata = SES_MALLOC(16); 2443 if (sdata == NULL) 2444 return (ENOMEM); 2445 2446 SES_DLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3); 2447 2448 sdata[0] = op; 2449 sdata[1] = b1; 2450 sdata[2] = b2; 2451 sdata[3] = b3; 2452 MEMZERO(&sdata[4], 12); 2453 amt = -16; 2454 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2455 SES_FREE(sdata, 16); 2456 return (err); 2457 } 2458 2459 /* 2460 * This function updates the status byte for the device slot described. 2461 * 2462 * Since this is an optional SAF-TE command, there's no point in 2463 * returning an error. 2464 */ 2465 static void 2466 wrslot_stat(ses_softc_t *ssc, int slp) 2467 { 2468 int i, amt; 2469 encobj *ep; 2470 char cdb[10], *sdata; 2471 struct scfg *cc = ssc->ses_private; 2472 2473 if (cc == NULL) 2474 return; 2475 2476 SES_DLOG(ssc, "saf_wrslot\n"); 2477 cdb[0] = WRITE_BUFFER; 2478 cdb[1] = 1; 2479 cdb[2] = 0; 2480 cdb[3] = 0; 2481 cdb[4] = 0; 2482 cdb[5] = 0; 2483 cdb[6] = 0; 2484 cdb[7] = 0; 2485 cdb[8] = cc->Nslots * 3 + 1; 2486 cdb[9] = 0; 2487 2488 sdata = SES_MALLOC(cc->Nslots * 3 + 1); 2489 if (sdata == NULL) 2490 return; 2491 MEMZERO(sdata, cc->Nslots * 3 + 1); 2492 2493 sdata[0] = SAFTE_WT_DSTAT; 2494 for (i = 0; i < cc->Nslots; i++) { 2495 ep = &ssc->ses_objmap[cc->slotoff + i]; 2496 SES_DLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff); 2497 sdata[1 + (3 * i)] = ep->priv & 0xff; 2498 } 2499 amt = -(cc->Nslots * 3 + 1); 2500 ses_runcmd(ssc, cdb, 10, sdata, &amt); 2501 SES_FREE(sdata, cc->Nslots * 3 + 1); 2502 } 2503 2504 /* 2505 * This function issues the "PERFORM SLOT OPERATION" command. 2506 */ 2507 static int 2508 perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp) 2509 { 2510 int err, amt; 2511 char *sdata; 2512 struct scfg *cc = ssc->ses_private; 2513 static char cdb[10] = 2514 { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 2515 2516 if (cc == NULL) 2517 return (0); 2518 2519 sdata = SES_MALLOC(SAFT_SCRATCH); 2520 if (sdata == NULL) 2521 return (ENOMEM); 2522 MEMZERO(sdata, SAFT_SCRATCH); 2523 2524 sdata[0] = SAFTE_WT_SLTOP; 2525 sdata[1] = slot; 2526 sdata[2] = opflag; 2527 SES_DLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag); 2528 amt = -SAFT_SCRATCH; 2529 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2530 SES_FREE(sdata, SAFT_SCRATCH); 2531 return (err); 2532 } 2533