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