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