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 <sys/ioccom.h> 54 #include "scsi_ses.h" 55 56 #include <opt_ses.h> 57 58 MALLOC_DEFINE(M_SCSISES, "SCSI SES", "SCSI SES buffers"); 59 60 /* 61 * Platform Independent Driver Internal Definitions for SES devices. 62 */ 63 typedef enum { 64 SES_NONE, 65 SES_SES_SCSI2, 66 SES_SES, 67 SES_SES_PASSTHROUGH, 68 SES_SEN, 69 SES_SAFT 70 } enctyp; 71 72 struct ses_softc; 73 typedef struct ses_softc ses_softc_t; 74 typedef struct { 75 int (*softc_init)(ses_softc_t *, int); 76 int (*init_enc)(ses_softc_t *); 77 int (*get_encstat)(ses_softc_t *, int); 78 int (*set_encstat)(ses_softc_t *, ses_encstat, int); 79 int (*get_objstat)(ses_softc_t *, ses_objstat *, int); 80 int (*set_objstat)(ses_softc_t *, ses_objstat *, int); 81 } encvec; 82 83 #define ENCI_SVALID 0x80 84 85 typedef struct { 86 uint32_t 87 enctype : 8, /* enclosure type */ 88 subenclosure : 8, /* subenclosure id */ 89 svalid : 1, /* enclosure information valid */ 90 priv : 15; /* private data, per object */ 91 uint8_t encstat[4]; /* state && stats */ 92 } encobj; 93 94 #define SEN_ID "UNISYS SUN_SEN" 95 #define SEN_ID_LEN 24 96 97 98 static enctyp ses_type(void *, int); 99 100 101 /* Forward reference to Enclosure Functions */ 102 static int ses_softc_init(ses_softc_t *, int); 103 static int ses_init_enc(ses_softc_t *); 104 static int ses_get_encstat(ses_softc_t *, int); 105 static int ses_set_encstat(ses_softc_t *, uint8_t, int); 106 static int ses_get_objstat(ses_softc_t *, ses_objstat *, int); 107 static int ses_set_objstat(ses_softc_t *, ses_objstat *, int); 108 109 static int safte_softc_init(ses_softc_t *, int); 110 static int safte_init_enc(ses_softc_t *); 111 static int safte_get_encstat(ses_softc_t *, int); 112 static int safte_set_encstat(ses_softc_t *, uint8_t, int); 113 static int safte_get_objstat(ses_softc_t *, ses_objstat *, int); 114 static int safte_set_objstat(ses_softc_t *, ses_objstat *, int); 115 116 /* 117 * Platform implementation defines/functions for SES internal kernel stuff 118 */ 119 120 #define STRNCMP strncmp 121 #define PRINTF kprintf 122 #define SES_LOG ses_log 123 #ifdef DEBUG 124 #define SES_DLOG ses_log 125 #else 126 #define SES_DLOG if (0) ses_log 127 #endif 128 #define SES_VLOG if (bootverbose) ses_log 129 #define SES_MALLOC(amt) kmalloc(amt, M_SCSISES, M_INTWAIT) 130 #define SES_FREE(ptr, amt) kfree(ptr, M_SCSISES) 131 #define MEMZERO bzero 132 #define MEMCPY(dest, src, amt) bcopy(src, dest, amt) 133 134 static int ses_runcmd(struct ses_softc *, char *, int, char *, int *); 135 static void ses_log(struct ses_softc *, const char *, ...); 136 137 /* 138 * Gerenal FreeBSD kernel stuff. 139 */ 140 141 142 #define ccb_state ppriv_field0 143 #define ccb_bio ppriv_ptr1 144 145 struct ses_softc { 146 enctyp ses_type; /* type of enclosure */ 147 encvec ses_vec; /* vector to handlers */ 148 void * ses_private; /* per-type private data */ 149 encobj * ses_objmap; /* objects */ 150 u_int32_t ses_nobjects; /* number of objects */ 151 ses_encstat ses_encstat; /* overall status */ 152 u_int8_t ses_flags; 153 union ccb ses_saved_ccb; 154 struct cam_periph *periph; 155 }; 156 #define SES_FLAG_INVALID 0x01 157 #define SES_FLAG_OPEN 0x02 158 #define SES_FLAG_INITIALIZED 0x04 159 160 #define SESUNIT(x) (minor((x))) 161 #define SES_CDEV_MAJOR 110 162 163 static d_open_t sesopen; 164 static d_close_t sesclose; 165 static d_ioctl_t sesioctl; 166 static periph_init_t sesinit; 167 static periph_ctor_t sesregister; 168 static periph_oninv_t sesoninvalidate; 169 static periph_dtor_t sescleanup; 170 static periph_start_t sesstart; 171 172 static void sesasync(void *, u_int32_t, struct cam_path *, void *); 173 static void sesdone(struct cam_periph *, union ccb *); 174 static int seserror(union ccb *, u_int32_t, u_int32_t); 175 176 static struct periph_driver sesdriver = { 177 sesinit, "ses", 178 TAILQ_HEAD_INITIALIZER(sesdriver.units), /* generation */ 0 179 }; 180 181 PERIPHDRIVER_DECLARE(ses, sesdriver); 182 183 static struct dev_ops ses_ops = { 184 { "ses", SES_CDEV_MAJOR, 0 }, 185 .d_open = sesopen, 186 .d_close = sesclose, 187 .d_ioctl = sesioctl, 188 }; 189 static struct extend_array *sesperiphs; 190 191 static void 192 sesinit(void) 193 { 194 cam_status status; 195 196 /* 197 * Create our extend array for storing the devices we attach to. 198 */ 199 sesperiphs = cam_extend_new(); 200 if (sesperiphs == NULL) { 201 kprintf("ses: Failed to alloc extend array!\n"); 202 return; 203 } 204 205 /* 206 * Install a global async callback. This callback will 207 * receive async callbacks like "new device found". 208 */ 209 status = xpt_register_async(AC_FOUND_DEVICE, sesasync, NULL, NULL); 210 211 if (status != CAM_REQ_CMP) { 212 kprintf("ses: Failed to attach master async callback " 213 "due to status 0x%x!\n", status); 214 } 215 } 216 217 static void 218 sesoninvalidate(struct cam_periph *periph) 219 { 220 struct ses_softc *softc; 221 222 softc = (struct ses_softc *)periph->softc; 223 224 /* 225 * Unregister any async callbacks. 226 */ 227 xpt_register_async(0, sesasync, periph, periph->path); 228 229 softc->ses_flags |= SES_FLAG_INVALID; 230 231 xpt_print(periph->path, "lost device\n"); 232 } 233 234 static void 235 sescleanup(struct cam_periph *periph) 236 { 237 struct ses_softc *softc; 238 239 softc = (struct ses_softc *)periph->softc; 240 241 cam_extend_release(sesperiphs, periph->unit_number); 242 xpt_print(periph->path, "removing device entry\n"); 243 dev_ops_remove(&ses_ops, -1, periph->unit_number); 244 kfree(softc, M_SCSISES); 245 } 246 247 static void 248 sesasync(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg) 249 { 250 struct cam_periph *periph; 251 252 periph = (struct cam_periph *)callback_arg; 253 254 switch(code) { 255 case AC_FOUND_DEVICE: 256 { 257 cam_status status; 258 struct ccb_getdev *cgd; 259 int inq_len; 260 261 cgd = (struct ccb_getdev *)arg; 262 if (arg == NULL) { 263 break; 264 } 265 266 inq_len = cgd->inq_data.additional_length + 4; 267 268 /* 269 * PROBLEM: WE NEED TO LOOK AT BYTES 48-53 TO SEE IF THIS IS 270 * PROBLEM: IS A SAF-TE DEVICE. 271 */ 272 switch (ses_type(&cgd->inq_data, inq_len)) { 273 case SES_SES: 274 case SES_SES_SCSI2: 275 case SES_SES_PASSTHROUGH: 276 case SES_SEN: 277 case SES_SAFT: 278 break; 279 default: 280 return; 281 } 282 283 status = cam_periph_alloc(sesregister, sesoninvalidate, 284 sescleanup, sesstart, "ses", CAM_PERIPH_BIO, 285 cgd->ccb_h.path, sesasync, AC_FOUND_DEVICE, cgd); 286 287 if (status != CAM_REQ_CMP && status != CAM_REQ_INPROG) { 288 kprintf("sesasync: Unable to probe new device due to " 289 "status 0x%x\n", status); 290 } 291 break; 292 } 293 default: 294 cam_periph_async(periph, code, path, arg); 295 break; 296 } 297 } 298 299 static cam_status 300 sesregister(struct cam_periph *periph, void *arg) 301 { 302 struct ses_softc *softc; 303 struct ccb_getdev *cgd; 304 char *tname; 305 306 cgd = (struct ccb_getdev *)arg; 307 if (periph == NULL) { 308 kprintf("sesregister: periph was NULL!!\n"); 309 return (CAM_REQ_CMP_ERR); 310 } 311 312 if (cgd == NULL) { 313 kprintf("sesregister: no getdev CCB, can't register device\n"); 314 return (CAM_REQ_CMP_ERR); 315 } 316 317 softc = kmalloc(sizeof (struct ses_softc), M_SCSISES, M_INTWAIT | M_ZERO); 318 periph->softc = softc; 319 softc->periph = periph; 320 321 softc->ses_type = ses_type(&cgd->inq_data, sizeof (cgd->inq_data)); 322 323 switch (softc->ses_type) { 324 case SES_SES: 325 case SES_SES_SCSI2: 326 case SES_SES_PASSTHROUGH: 327 softc->ses_vec.softc_init = ses_softc_init; 328 softc->ses_vec.init_enc = ses_init_enc; 329 softc->ses_vec.get_encstat = ses_get_encstat; 330 softc->ses_vec.set_encstat = ses_set_encstat; 331 softc->ses_vec.get_objstat = ses_get_objstat; 332 softc->ses_vec.set_objstat = ses_set_objstat; 333 break; 334 case SES_SAFT: 335 softc->ses_vec.softc_init = safte_softc_init; 336 softc->ses_vec.init_enc = safte_init_enc; 337 softc->ses_vec.get_encstat = safte_get_encstat; 338 softc->ses_vec.set_encstat = safte_set_encstat; 339 softc->ses_vec.get_objstat = safte_get_objstat; 340 softc->ses_vec.set_objstat = safte_set_objstat; 341 break; 342 case SES_SEN: 343 break; 344 case SES_NONE: 345 default: 346 kfree(softc, M_SCSISES); 347 return (CAM_REQ_CMP_ERR); 348 } 349 350 cam_extend_set(sesperiphs, periph->unit_number, periph); 351 352 cam_periph_unlock(periph); 353 dev_ops_add(&ses_ops, -1, periph->unit_number); 354 make_dev(&ses_ops, periph->unit_number, 355 UID_ROOT, GID_OPERATOR, 0600, "%s%d", 356 periph->periph_name, periph->unit_number); 357 cam_periph_lock(periph); 358 359 /* 360 * Add an async callback so that we get 361 * notified if this device goes away. 362 */ 363 xpt_register_async(AC_LOST_DEVICE, sesasync, periph, periph->path); 364 365 switch (softc->ses_type) { 366 default: 367 case SES_NONE: 368 tname = "No SES device"; 369 break; 370 case SES_SES_SCSI2: 371 tname = "SCSI-2 SES Device"; 372 break; 373 case SES_SES: 374 tname = "SCSI-3 SES Device"; 375 break; 376 case SES_SES_PASSTHROUGH: 377 tname = "SES Passthrough Device"; 378 break; 379 case SES_SEN: 380 tname = "UNISYS SEN Device (NOT HANDLED YET)"; 381 break; 382 case SES_SAFT: 383 tname = "SAF-TE Compliant Device"; 384 break; 385 } 386 xpt_announce_periph(periph, tname); 387 return (CAM_REQ_CMP); 388 } 389 390 static int 391 sesopen(struct dev_open_args *ap) 392 { 393 cdev_t dev = ap->a_head.a_dev; 394 struct cam_periph *periph; 395 struct ses_softc *softc; 396 int error = 0; 397 398 periph = cam_extend_get(sesperiphs, SESUNIT(dev)); 399 if (periph == NULL) { 400 return (ENXIO); 401 } 402 403 if (cam_periph_acquire(periph) != CAM_REQ_CMP) { 404 cam_periph_unlock(periph); 405 return (ENXIO); 406 } 407 408 cam_periph_lock(periph); 409 410 softc = (struct ses_softc *)periph->softc; 411 412 if (softc->ses_flags & SES_FLAG_INVALID) { 413 error = ENXIO; 414 goto out; 415 } 416 if (softc->ses_flags & SES_FLAG_OPEN) { 417 error = EBUSY; 418 goto out; 419 } 420 if (softc->ses_vec.softc_init == NULL) { 421 error = ENXIO; 422 goto out; 423 } 424 425 softc->ses_flags |= SES_FLAG_OPEN; 426 if ((softc->ses_flags & SES_FLAG_INITIALIZED) == 0) { 427 error = (*softc->ses_vec.softc_init)(softc, 1); 428 if (error) 429 softc->ses_flags &= ~SES_FLAG_OPEN; 430 else 431 softc->ses_flags |= SES_FLAG_INITIALIZED; 432 } 433 434 out: 435 cam_periph_unlock(periph); 436 if (error) { 437 cam_periph_release(periph); 438 } 439 return (error); 440 } 441 442 static int 443 sesclose(struct dev_close_args *ap) 444 { 445 cdev_t dev = ap->a_head.a_dev; 446 struct cam_periph *periph; 447 struct ses_softc *softc; 448 int unit, error; 449 450 error = 0; 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 cc = ssc->ses_private; 1223 if (cc == NULL) { 1224 return (ENXIO); 1225 } 1226 1227 /* 1228 * If we're just getting overall enclosure status, 1229 * we only need 2 bytes of data storage. 1230 * 1231 * If we're getting anything else, we know how much 1232 * storage we need by noting that starting at offset 1233 * 8 in returned data, all object status bytes are 4 1234 * bytes long, and are stored in chunks of types(M) 1235 * and nth+1 instances of type M. 1236 */ 1237 if (objid == -1) { 1238 bufsiz = 2; 1239 } else { 1240 bufsiz = (ssc->ses_nobjects * 4) + (cc->ses_ntypes * 4) + 8; 1241 } 1242 sdata = SES_MALLOC(bufsiz); 1243 if (sdata == NULL) 1244 return (ENOMEM); 1245 1246 cdb[0] = RECEIVE_DIAGNOSTIC; 1247 cdb[1] = 1; 1248 cdb[2] = SesStatusPage; 1249 cdb[3] = bufsiz >> 8; 1250 cdb[4] = bufsiz & 0xff; 1251 cdb[5] = 0; 1252 amt = bufsiz; 1253 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1254 if (err) { 1255 SES_FREE(sdata, bufsiz); 1256 return (err); 1257 } 1258 amt = bufsiz - amt; 1259 1260 if (objid == -1) { 1261 tidx = -1; 1262 oidx = -1; 1263 } else { 1264 tidx = cc->ses_typidx[objid].ses_tidx; 1265 oidx = cc->ses_typidx[objid].ses_oidx; 1266 } 1267 if (in) { 1268 if (ses_decode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1269 err = ENODEV; 1270 } 1271 } else { 1272 if (ses_encode(sdata, amt, cc->ses_eltmap, tidx, oidx, sp)) { 1273 err = ENODEV; 1274 } else { 1275 cdb[0] = SEND_DIAGNOSTIC; 1276 cdb[1] = 0x10; 1277 cdb[2] = 0; 1278 cdb[3] = bufsiz >> 8; 1279 cdb[4] = bufsiz & 0xff; 1280 cdb[5] = 0; 1281 amt = -bufsiz; 1282 err = ses_runcmd(ssc, cdb, 6, sdata, &amt); 1283 } 1284 } 1285 SES_FREE(sdata, bufsiz); 1286 return (0); 1287 } 1288 1289 1290 /* 1291 * Routines to parse returned SES data structures. 1292 * Architecture and compiler independent. 1293 */ 1294 1295 static int 1296 ses_cfghdr(uint8_t *buffer, int buflen, SesCfgHdr *cfp) 1297 { 1298 if (buflen < SES_CFGHDR_MINLEN) { 1299 return (-1); 1300 } 1301 gget8(buffer, 1, cfp->Nsubenc); 1302 gget32(buffer, 4, cfp->GenCode); 1303 return (0); 1304 } 1305 1306 static int 1307 ses_enchdr(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncHdr *chp) 1308 { 1309 int s, off = 8; 1310 for (s = 0; s < SubEncId; s++) { 1311 if (off + 3 > amt) 1312 return (-1); 1313 off += buffer[off+3] + 4; 1314 } 1315 if (off + 3 > amt) { 1316 return (-1); 1317 } 1318 gget8(buffer, off+1, chp->Subencid); 1319 gget8(buffer, off+2, chp->Ntypes); 1320 gget8(buffer, off+3, chp->VEnclen); 1321 return (0); 1322 } 1323 1324 static int 1325 ses_encdesc(uint8_t *buffer, int amt, uint8_t SubEncId, SesEncDesc *cdp) 1326 { 1327 int s, e, enclen, off = 8; 1328 for (s = 0; s < SubEncId; s++) { 1329 if (off + 3 > amt) 1330 return (-1); 1331 off += buffer[off+3] + 4; 1332 } 1333 if (off + 3 > amt) { 1334 return (-1); 1335 } 1336 gget8(buffer, off+3, enclen); 1337 off += 4; 1338 if (off >= amt) 1339 return (-1); 1340 1341 e = off + enclen; 1342 if (e > amt) { 1343 e = amt; 1344 } 1345 MEMCPY(cdp, &buffer[off], e - off); 1346 return (0); 1347 } 1348 1349 static int 1350 ses_getthdr(uint8_t *buffer, int amt, int nth, SesThdr *thp) 1351 { 1352 int s, off = 8; 1353 1354 if (amt < SES_CFGHDR_MINLEN) { 1355 return (-1); 1356 } 1357 for (s = 0; s < buffer[1]; s++) { 1358 if (off + 3 > amt) 1359 return (-1); 1360 off += buffer[off+3] + 4; 1361 } 1362 if (off + 3 > amt) { 1363 return (-1); 1364 } 1365 off += buffer[off+3] + 4 + (nth * 4); 1366 if (amt < (off + 4)) 1367 return (-1); 1368 1369 gget8(buffer, off++, thp->enc_type); 1370 gget8(buffer, off++, thp->enc_maxelt); 1371 gget8(buffer, off++, thp->enc_subenc); 1372 gget8(buffer, off, thp->enc_tlen); 1373 return (0); 1374 } 1375 1376 /* 1377 * This function needs a little explanation. 1378 * 1379 * The arguments are: 1380 * 1381 * 1382 * char *b, int amt 1383 * 1384 * These describes the raw input SES status data and length. 1385 * 1386 * uint8_t *ep 1387 * 1388 * This is a map of the number of types for each element type 1389 * in the enclosure. 1390 * 1391 * int elt 1392 * 1393 * This is the element type being sought. If elt is -1, 1394 * then overall enclosure status is being sought. 1395 * 1396 * int elm 1397 * 1398 * This is the ordinal Mth element of type elt being sought. 1399 * 1400 * SesComStat *sp 1401 * 1402 * This is the output area to store the status for 1403 * the Mth element of type Elt. 1404 */ 1405 1406 static int 1407 ses_decode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1408 { 1409 int idx, i; 1410 1411 /* 1412 * If it's overall enclosure status being sought, get that. 1413 * We need at least 2 bytes of status data to get that. 1414 */ 1415 if (elt == -1) { 1416 if (amt < 2) 1417 return (-1); 1418 gget8(b, 1, sp->comstatus); 1419 sp->comstat[0] = 0; 1420 sp->comstat[1] = 0; 1421 sp->comstat[2] = 0; 1422 return (0); 1423 } 1424 1425 /* 1426 * Check to make sure that the Mth element is legal for type Elt. 1427 */ 1428 1429 if (elm >= ep[elt]) 1430 return (-1); 1431 1432 /* 1433 * Starting at offset 8, start skipping over the storage 1434 * for the element types we're not interested in. 1435 */ 1436 for (idx = 8, i = 0; i < elt; i++) { 1437 idx += ((ep[i] + 1) * 4); 1438 } 1439 1440 /* 1441 * Skip over Overall status for this element type. 1442 */ 1443 idx += 4; 1444 1445 /* 1446 * And skip to the index for the Mth element that we're going for. 1447 */ 1448 idx += (4 * elm); 1449 1450 /* 1451 * Make sure we haven't overflowed the buffer. 1452 */ 1453 if (idx+4 > amt) 1454 return (-1); 1455 1456 /* 1457 * Retrieve the status. 1458 */ 1459 gget8(b, idx++, sp->comstatus); 1460 gget8(b, idx++, sp->comstat[0]); 1461 gget8(b, idx++, sp->comstat[1]); 1462 gget8(b, idx++, sp->comstat[2]); 1463 #if 0 1464 PRINTF("Get Elt 0x%x Elm 0x%x (idx %d)\n", elt, elm, idx-4); 1465 #endif 1466 return (0); 1467 } 1468 1469 /* 1470 * This is the mirror function to ses_decode, but we set the 'select' 1471 * bit for the object which we're interested in. All other objects, 1472 * after a status fetch, should have that bit off. Hmm. It'd be easy 1473 * enough to ensure this, so we will. 1474 */ 1475 1476 static int 1477 ses_encode(char *b, int amt, uint8_t *ep, int elt, int elm, SesComStat *sp) 1478 { 1479 int idx, i; 1480 1481 /* 1482 * If it's overall enclosure status being sought, get that. 1483 * We need at least 2 bytes of status data to get that. 1484 */ 1485 if (elt == -1) { 1486 if (amt < 2) 1487 return (-1); 1488 i = 0; 1489 sset8(b, i, 0); 1490 sset8(b, i, sp->comstatus & 0xf); 1491 #if 0 1492 PRINTF("set EncStat %x\n", sp->comstatus); 1493 #endif 1494 return (0); 1495 } 1496 1497 /* 1498 * Check to make sure that the Mth element is legal for type Elt. 1499 */ 1500 1501 if (elm >= ep[elt]) 1502 return (-1); 1503 1504 /* 1505 * Starting at offset 8, start skipping over the storage 1506 * for the element types we're not interested in. 1507 */ 1508 for (idx = 8, i = 0; i < elt; i++) { 1509 idx += ((ep[i] + 1) * 4); 1510 } 1511 1512 /* 1513 * Skip over Overall status for this element type. 1514 */ 1515 idx += 4; 1516 1517 /* 1518 * And skip to the index for the Mth element that we're going for. 1519 */ 1520 idx += (4 * elm); 1521 1522 /* 1523 * Make sure we haven't overflowed the buffer. 1524 */ 1525 if (idx+4 > amt) 1526 return (-1); 1527 1528 /* 1529 * Set the status. 1530 */ 1531 sset8(b, idx, sp->comstatus); 1532 sset8(b, idx, sp->comstat[0]); 1533 sset8(b, idx, sp->comstat[1]); 1534 sset8(b, idx, sp->comstat[2]); 1535 idx -= 4; 1536 1537 #if 0 1538 PRINTF("Set Elt 0x%x Elm 0x%x (idx %d) with %x %x %x %x\n", 1539 elt, elm, idx, sp->comstatus, sp->comstat[0], 1540 sp->comstat[1], sp->comstat[2]); 1541 #endif 1542 1543 /* 1544 * Now make sure all other 'Select' bits are off. 1545 */ 1546 for (i = 8; i < amt; i += 4) { 1547 if (i != idx) 1548 b[i] &= ~0x80; 1549 } 1550 /* 1551 * And make sure the INVOP bit is clear. 1552 */ 1553 b[2] &= ~0x10; 1554 1555 return (0); 1556 } 1557 1558 /* 1559 * SAF-TE Type Device Emulation 1560 */ 1561 1562 static int safte_getconfig(ses_softc_t *); 1563 static int safte_rdstat(ses_softc_t *, int); 1564 static int set_objstat_sel(ses_softc_t *, ses_objstat *, int); 1565 static int wrbuf16(ses_softc_t *, uint8_t, uint8_t, uint8_t, uint8_t, int); 1566 static void wrslot_stat(ses_softc_t *, int); 1567 static int perf_slotop(ses_softc_t *, uint8_t, uint8_t, int); 1568 1569 #define ALL_ENC_STAT (SES_ENCSTAT_CRITICAL | SES_ENCSTAT_UNRECOV | \ 1570 SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO) 1571 /* 1572 * SAF-TE specific defines- Mandatory ones only... 1573 */ 1574 1575 /* 1576 * READ BUFFER ('get' commands) IDs- placed in offset 2 of cdb 1577 */ 1578 #define SAFTE_RD_RDCFG 0x00 /* read enclosure configuration */ 1579 #define SAFTE_RD_RDESTS 0x01 /* read enclosure status */ 1580 #define SAFTE_RD_RDDSTS 0x04 /* read drive slot status */ 1581 1582 /* 1583 * WRITE BUFFER ('set' commands) IDs- placed in offset 0 of databuf 1584 */ 1585 #define SAFTE_WT_DSTAT 0x10 /* write device slot status */ 1586 #define SAFTE_WT_SLTOP 0x12 /* perform slot operation */ 1587 #define SAFTE_WT_FANSPD 0x13 /* set fan speed */ 1588 #define SAFTE_WT_ACTPWS 0x14 /* turn on/off power supply */ 1589 #define SAFTE_WT_GLOBAL 0x15 /* send global command */ 1590 1591 1592 #define SAFT_SCRATCH 64 1593 #define NPSEUDO_THERM 16 1594 #define NPSEUDO_ALARM 1 1595 struct scfg { 1596 /* 1597 * Cached Configuration 1598 */ 1599 uint8_t Nfans; /* Number of Fans */ 1600 uint8_t Npwr; /* Number of Power Supplies */ 1601 uint8_t Nslots; /* Number of Device Slots */ 1602 uint8_t DoorLock; /* Door Lock Installed */ 1603 uint8_t Ntherm; /* Number of Temperature Sensors */ 1604 uint8_t Nspkrs; /* Number of Speakers */ 1605 uint8_t Nalarm; /* Number of Alarms (at least one) */ 1606 /* 1607 * Cached Flag Bytes for Global Status 1608 */ 1609 uint8_t flag1; 1610 uint8_t flag2; 1611 /* 1612 * What object index ID is where various slots start. 1613 */ 1614 uint8_t pwroff; 1615 uint8_t slotoff; 1616 #define SAFT_ALARM_OFFSET(cc) (cc)->slotoff - 1 1617 }; 1618 1619 #define SAFT_FLG1_ALARM 0x1 1620 #define SAFT_FLG1_GLOBFAIL 0x2 1621 #define SAFT_FLG1_GLOBWARN 0x4 1622 #define SAFT_FLG1_ENCPWROFF 0x8 1623 #define SAFT_FLG1_ENCFANFAIL 0x10 1624 #define SAFT_FLG1_ENCPWRFAIL 0x20 1625 #define SAFT_FLG1_ENCDRVFAIL 0x40 1626 #define SAFT_FLG1_ENCDRVWARN 0x80 1627 1628 #define SAFT_FLG2_LOCKDOOR 0x4 1629 #define SAFT_PRIVATE sizeof (struct scfg) 1630 1631 static char *safte_2little = "Too Little Data Returned (%d) at line %d\n"; 1632 #define SAFT_BAIL(r, x, k, l) \ 1633 if ((r) >= (x)) { \ 1634 SES_LOG(ssc, safte_2little, x, __LINE__);\ 1635 SES_FREE((k), (l)); \ 1636 return (EIO); \ 1637 } 1638 1639 1640 static int 1641 safte_softc_init(ses_softc_t *ssc, int doinit) 1642 { 1643 int err, i, r; 1644 struct scfg *cc; 1645 1646 if (doinit == 0) { 1647 if (ssc->ses_nobjects) { 1648 if (ssc->ses_objmap) { 1649 SES_FREE(ssc->ses_objmap, 1650 ssc->ses_nobjects * sizeof (encobj)); 1651 ssc->ses_objmap = NULL; 1652 } 1653 ssc->ses_nobjects = 0; 1654 } 1655 if (ssc->ses_private) { 1656 SES_FREE(ssc->ses_private, SAFT_PRIVATE); 1657 ssc->ses_private = NULL; 1658 } 1659 return (0); 1660 } 1661 1662 if (ssc->ses_private == NULL) { 1663 ssc->ses_private = SES_MALLOC(SAFT_PRIVATE); 1664 if (ssc->ses_private == NULL) { 1665 return (ENOMEM); 1666 } 1667 MEMZERO(ssc->ses_private, SAFT_PRIVATE); 1668 } 1669 1670 ssc->ses_nobjects = 0; 1671 ssc->ses_encstat = 0; 1672 1673 if ((err = safte_getconfig(ssc)) != 0) { 1674 return (err); 1675 } 1676 1677 /* 1678 * The number of objects here, as well as that reported by the 1679 * READ_BUFFER/GET_CONFIG call, are the over-temperature flags (15) 1680 * that get reported during READ_BUFFER/READ_ENC_STATUS. 1681 */ 1682 cc = ssc->ses_private; 1683 ssc->ses_nobjects = cc->Nfans + cc->Npwr + cc->Nslots + cc->DoorLock + 1684 cc->Ntherm + cc->Nspkrs + NPSEUDO_THERM + NPSEUDO_ALARM; 1685 ssc->ses_objmap = (encobj *) 1686 SES_MALLOC(ssc->ses_nobjects * sizeof (encobj)); 1687 if (ssc->ses_objmap == NULL) { 1688 return (ENOMEM); 1689 } 1690 MEMZERO(ssc->ses_objmap, ssc->ses_nobjects * sizeof (encobj)); 1691 1692 r = 0; 1693 /* 1694 * Note that this is all arranged for the convenience 1695 * in later fetches of status. 1696 */ 1697 for (i = 0; i < cc->Nfans; i++) 1698 ssc->ses_objmap[r++].enctype = SESTYP_FAN; 1699 cc->pwroff = (uint8_t) r; 1700 for (i = 0; i < cc->Npwr; i++) 1701 ssc->ses_objmap[r++].enctype = SESTYP_POWER; 1702 for (i = 0; i < cc->DoorLock; i++) 1703 ssc->ses_objmap[r++].enctype = SESTYP_DOORLOCK; 1704 for (i = 0; i < cc->Nspkrs; i++) 1705 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1706 for (i = 0; i < cc->Ntherm; i++) 1707 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1708 for (i = 0; i < NPSEUDO_THERM; i++) 1709 ssc->ses_objmap[r++].enctype = SESTYP_THERM; 1710 ssc->ses_objmap[r++].enctype = SESTYP_ALARM; 1711 cc->slotoff = (uint8_t) r; 1712 for (i = 0; i < cc->Nslots; i++) 1713 ssc->ses_objmap[r++].enctype = SESTYP_DEVICE; 1714 return (0); 1715 } 1716 1717 static int 1718 safte_init_enc(ses_softc_t *ssc) 1719 { 1720 int err; 1721 static char cdb0[6] = { SEND_DIAGNOSTIC }; 1722 1723 err = ses_runcmd(ssc, cdb0, 6, NULL, 0); 1724 if (err) { 1725 return (err); 1726 } 1727 DELAY(5000); 1728 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, 0, 0, 0, 1); 1729 return (err); 1730 } 1731 1732 static int 1733 safte_get_encstat(ses_softc_t *ssc, int slpflg) 1734 { 1735 return (safte_rdstat(ssc, slpflg)); 1736 } 1737 1738 static int 1739 safte_set_encstat(ses_softc_t *ssc, uint8_t encstat, int slpflg) 1740 { 1741 struct scfg *cc = ssc->ses_private; 1742 if (cc == NULL) 1743 return (0); 1744 /* 1745 * Since SAF-TE devices aren't necessarily sticky in terms 1746 * of state, make our soft copy of enclosure status 'sticky'- 1747 * that is, things set in enclosure status stay set (as implied 1748 * by conditions set in reading object status) until cleared. 1749 */ 1750 ssc->ses_encstat &= ~ALL_ENC_STAT; 1751 ssc->ses_encstat |= (encstat & ALL_ENC_STAT); 1752 ssc->ses_encstat |= ENCI_SVALID; 1753 cc->flag1 &= ~(SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL|SAFT_FLG1_GLOBWARN); 1754 if ((encstat & (SES_ENCSTAT_CRITICAL|SES_ENCSTAT_UNRECOV)) != 0) { 1755 cc->flag1 |= SAFT_FLG1_ALARM|SAFT_FLG1_GLOBFAIL; 1756 } else if ((encstat & SES_ENCSTAT_NONCRITICAL) != 0) { 1757 cc->flag1 |= SAFT_FLG1_GLOBWARN; 1758 } 1759 return (wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slpflg)); 1760 } 1761 1762 static int 1763 safte_get_objstat(ses_softc_t *ssc, ses_objstat *obp, int slpflg) 1764 { 1765 int i = (int)obp->obj_id; 1766 1767 if ((ssc->ses_encstat & ENCI_SVALID) == 0 || 1768 (ssc->ses_objmap[i].svalid) == 0) { 1769 int err = safte_rdstat(ssc, slpflg); 1770 if (err) 1771 return (err); 1772 } 1773 obp->cstat[0] = ssc->ses_objmap[i].encstat[0]; 1774 obp->cstat[1] = ssc->ses_objmap[i].encstat[1]; 1775 obp->cstat[2] = ssc->ses_objmap[i].encstat[2]; 1776 obp->cstat[3] = ssc->ses_objmap[i].encstat[3]; 1777 return (0); 1778 } 1779 1780 1781 static int 1782 safte_set_objstat(ses_softc_t *ssc, ses_objstat *obp, int slp) 1783 { 1784 int idx, err; 1785 encobj *ep; 1786 struct scfg *cc; 1787 1788 1789 SES_DLOG(ssc, "safte_set_objstat(%d): %x %x %x %x\n", 1790 (int)obp->obj_id, obp->cstat[0], obp->cstat[1], obp->cstat[2], 1791 obp->cstat[3]); 1792 1793 /* 1794 * If this is clear, we don't do diddly. 1795 */ 1796 if ((obp->cstat[0] & SESCTL_CSEL) == 0) { 1797 return (0); 1798 } 1799 1800 err = 0; 1801 /* 1802 * Check to see if the common bits are set and do them first. 1803 */ 1804 if (obp->cstat[0] & ~SESCTL_CSEL) { 1805 err = set_objstat_sel(ssc, obp, slp); 1806 if (err) 1807 return (err); 1808 } 1809 1810 cc = ssc->ses_private; 1811 if (cc == NULL) 1812 return (0); 1813 1814 idx = (int)obp->obj_id; 1815 ep = &ssc->ses_objmap[idx]; 1816 1817 switch (ep->enctype) { 1818 case SESTYP_DEVICE: 1819 { 1820 uint8_t slotop = 0; 1821 /* 1822 * XXX: I should probably cache the previous state 1823 * XXX: of SESCTL_DEVOFF so that when it goes from 1824 * XXX: true to false I can then set PREPARE FOR OPERATION 1825 * XXX: flag in PERFORM SLOT OPERATION write buffer command. 1826 */ 1827 if (obp->cstat[2] & (SESCTL_RQSINS|SESCTL_RQSRMV)) { 1828 slotop |= 0x2; 1829 } 1830 if (obp->cstat[2] & SESCTL_RQSID) { 1831 slotop |= 0x4; 1832 } 1833 err = perf_slotop(ssc, (uint8_t) idx - (uint8_t) cc->slotoff, 1834 slotop, slp); 1835 if (err) 1836 return (err); 1837 if (obp->cstat[3] & SESCTL_RQSFLT) { 1838 ep->priv |= 0x2; 1839 } else { 1840 ep->priv &= ~0x2; 1841 } 1842 if (ep->priv & 0xc6) { 1843 ep->priv &= ~0x1; 1844 } else { 1845 ep->priv |= 0x1; /* no errors */ 1846 } 1847 wrslot_stat(ssc, slp); 1848 break; 1849 } 1850 case SESTYP_POWER: 1851 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1852 cc->flag1 |= SAFT_FLG1_ENCPWRFAIL; 1853 } else { 1854 cc->flag1 &= ~SAFT_FLG1_ENCPWRFAIL; 1855 } 1856 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1857 cc->flag2, 0, slp); 1858 if (err) 1859 return (err); 1860 if (obp->cstat[3] & SESCTL_RQSTON) { 1861 wrbuf16(ssc, SAFTE_WT_ACTPWS, 1862 idx - cc->pwroff, 0, 0, slp); 1863 } else { 1864 wrbuf16(ssc, SAFTE_WT_ACTPWS, 1865 idx - cc->pwroff, 0, 1, slp); 1866 } 1867 break; 1868 case SESTYP_FAN: 1869 if (obp->cstat[3] & SESCTL_RQSTFAIL) { 1870 cc->flag1 |= SAFT_FLG1_ENCFANFAIL; 1871 } else { 1872 cc->flag1 &= ~SAFT_FLG1_ENCFANFAIL; 1873 } 1874 err = wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 1875 cc->flag2, 0, slp); 1876 if (err) 1877 return (err); 1878 if (obp->cstat[3] & SESCTL_RQSTON) { 1879 uint8_t fsp; 1880 if ((obp->cstat[3] & 0x7) == 7) { 1881 fsp = 4; 1882 } else if ((obp->cstat[3] & 0x7) == 6) { 1883 fsp = 3; 1884 } else if ((obp->cstat[3] & 0x7) == 4) { 1885 fsp = 2; 1886 } else { 1887 fsp = 1; 1888 } 1889 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, fsp, 0, slp); 1890 } else { 1891 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 1892 } 1893 break; 1894 case SESTYP_DOORLOCK: 1895 if (obp->cstat[3] & 0x1) { 1896 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 1897 } else { 1898 cc->flag2 |= SAFT_FLG2_LOCKDOOR; 1899 } 1900 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slp); 1901 break; 1902 case SESTYP_ALARM: 1903 /* 1904 * On all nonzero but the 'muted' bit, we turn on the alarm, 1905 */ 1906 obp->cstat[3] &= ~0xa; 1907 if (obp->cstat[3] & 0x40) { 1908 cc->flag2 &= ~SAFT_FLG1_ALARM; 1909 } else if (obp->cstat[3] != 0) { 1910 cc->flag2 |= SAFT_FLG1_ALARM; 1911 } else { 1912 cc->flag2 &= ~SAFT_FLG1_ALARM; 1913 } 1914 ep->priv = obp->cstat[3]; 1915 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, cc->flag2, 0, slp); 1916 break; 1917 default: 1918 break; 1919 } 1920 ep->svalid = 0; 1921 return (0); 1922 } 1923 1924 static int 1925 safte_getconfig(ses_softc_t *ssc) 1926 { 1927 struct scfg *cfg; 1928 int err, amt; 1929 char *sdata; 1930 static char cdb[10] = 1931 { READ_BUFFER, 1, SAFTE_RD_RDCFG, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 1932 1933 cfg = ssc->ses_private; 1934 if (cfg == NULL) 1935 return (ENXIO); 1936 1937 sdata = SES_MALLOC(SAFT_SCRATCH); 1938 if (sdata == NULL) 1939 return (ENOMEM); 1940 1941 amt = SAFT_SCRATCH; 1942 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 1943 if (err) { 1944 SES_FREE(sdata, SAFT_SCRATCH); 1945 return (err); 1946 } 1947 amt = SAFT_SCRATCH - amt; 1948 if (amt < 6) { 1949 SES_LOG(ssc, "too little data (%d) for configuration\n", amt); 1950 SES_FREE(sdata, SAFT_SCRATCH); 1951 return (EIO); 1952 } 1953 SES_VLOG(ssc, "Nfans %d Npwr %d Nslots %d Lck %d Ntherm %d Nspkrs %d\n", 1954 sdata[0], sdata[1], sdata[2], sdata[3], sdata[4], sdata[5]); 1955 cfg->Nfans = sdata[0]; 1956 cfg->Npwr = sdata[1]; 1957 cfg->Nslots = sdata[2]; 1958 cfg->DoorLock = sdata[3]; 1959 cfg->Ntherm = sdata[4]; 1960 cfg->Nspkrs = sdata[5]; 1961 cfg->Nalarm = NPSEUDO_ALARM; 1962 SES_FREE(sdata, SAFT_SCRATCH); 1963 return (0); 1964 } 1965 1966 static int 1967 safte_rdstat(ses_softc_t *ssc, int slpflg) 1968 { 1969 int err, oid, r, i, hiwater, nitems, amt; 1970 uint16_t tempflags; 1971 size_t buflen; 1972 uint8_t status, oencstat; 1973 char *sdata, cdb[10]; 1974 struct scfg *cc = ssc->ses_private; 1975 1976 1977 /* 1978 * The number of objects overstates things a bit, 1979 * both for the bogus 'thermometer' entries and 1980 * the drive status (which isn't read at the same 1981 * time as the enclosure status), but that's okay. 1982 */ 1983 buflen = 4 * cc->Nslots; 1984 if (ssc->ses_nobjects > buflen) 1985 buflen = ssc->ses_nobjects; 1986 sdata = SES_MALLOC(buflen); 1987 if (sdata == NULL) 1988 return (ENOMEM); 1989 1990 cdb[0] = READ_BUFFER; 1991 cdb[1] = 1; 1992 cdb[2] = SAFTE_RD_RDESTS; 1993 cdb[3] = 0; 1994 cdb[4] = 0; 1995 cdb[5] = 0; 1996 cdb[6] = 0; 1997 cdb[7] = (buflen >> 8) & 0xff; 1998 cdb[8] = buflen & 0xff; 1999 cdb[9] = 0; 2000 amt = buflen; 2001 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2002 if (err) { 2003 SES_FREE(sdata, buflen); 2004 return (err); 2005 } 2006 hiwater = buflen - amt; 2007 2008 2009 /* 2010 * invalidate all status bits. 2011 */ 2012 for (i = 0; i < ssc->ses_nobjects; i++) 2013 ssc->ses_objmap[i].svalid = 0; 2014 oencstat = ssc->ses_encstat & ALL_ENC_STAT; 2015 ssc->ses_encstat = 0; 2016 2017 2018 /* 2019 * Now parse returned buffer. 2020 * If we didn't get enough data back, 2021 * that's considered a fatal error. 2022 */ 2023 oid = r = 0; 2024 2025 for (nitems = i = 0; i < cc->Nfans; i++) { 2026 SAFT_BAIL(r, hiwater, sdata, buflen); 2027 /* 2028 * 0 = Fan Operational 2029 * 1 = Fan is malfunctioning 2030 * 2 = Fan is not present 2031 * 0x80 = Unknown or Not Reportable Status 2032 */ 2033 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 2034 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 2035 switch ((int)(uint8_t)sdata[r]) { 2036 case 0: 2037 nitems++; 2038 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2039 /* 2040 * We could get fancier and cache 2041 * fan speeds that we have set, but 2042 * that isn't done now. 2043 */ 2044 ssc->ses_objmap[oid].encstat[3] = 7; 2045 break; 2046 2047 case 1: 2048 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2049 /* 2050 * FAIL and FAN STOPPED synthesized 2051 */ 2052 ssc->ses_objmap[oid].encstat[3] = 0x40; 2053 /* 2054 * Enclosure marked with CRITICAL error 2055 * if only one fan or no thermometers, 2056 * else the NONCRITICAL error is set. 2057 */ 2058 if (cc->Nfans == 1 || cc->Ntherm == 0) 2059 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2060 else 2061 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2062 break; 2063 case 2: 2064 ssc->ses_objmap[oid].encstat[0] = 2065 SES_OBJSTAT_NOTINSTALLED; 2066 ssc->ses_objmap[oid].encstat[3] = 0; 2067 /* 2068 * Enclosure marked with CRITICAL error 2069 * if only one fan or no thermometers, 2070 * else the NONCRITICAL error is set. 2071 */ 2072 if (cc->Nfans == 1) 2073 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2074 else 2075 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2076 break; 2077 case 0x80: 2078 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2079 ssc->ses_objmap[oid].encstat[3] = 0; 2080 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2081 break; 2082 default: 2083 ssc->ses_objmap[oid].encstat[0] = 2084 SES_OBJSTAT_UNSUPPORTED; 2085 SES_LOG(ssc, "Unknown fan%d status 0x%x\n", i, 2086 sdata[r] & 0xff); 2087 break; 2088 } 2089 ssc->ses_objmap[oid++].svalid = 1; 2090 r++; 2091 } 2092 2093 /* 2094 * No matter how you cut it, no cooling elements when there 2095 * should be some there is critical. 2096 */ 2097 if (cc->Nfans && nitems == 0) { 2098 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2099 } 2100 2101 2102 for (i = 0; i < cc->Npwr; i++) { 2103 SAFT_BAIL(r, hiwater, sdata, buflen); 2104 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2105 ssc->ses_objmap[oid].encstat[1] = 0; /* resvd */ 2106 ssc->ses_objmap[oid].encstat[2] = 0; /* resvd */ 2107 ssc->ses_objmap[oid].encstat[3] = 0x20; /* requested on */ 2108 switch ((uint8_t)sdata[r]) { 2109 case 0x00: /* pws operational and on */ 2110 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2111 break; 2112 case 0x01: /* pws operational and off */ 2113 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2114 ssc->ses_objmap[oid].encstat[3] = 0x10; 2115 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2116 break; 2117 case 0x10: /* pws is malfunctioning and commanded on */ 2118 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2119 ssc->ses_objmap[oid].encstat[3] = 0x61; 2120 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2121 break; 2122 2123 case 0x11: /* pws is malfunctioning and commanded off */ 2124 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 2125 ssc->ses_objmap[oid].encstat[3] = 0x51; 2126 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2127 break; 2128 case 0x20: /* pws is not present */ 2129 ssc->ses_objmap[oid].encstat[0] = 2130 SES_OBJSTAT_NOTINSTALLED; 2131 ssc->ses_objmap[oid].encstat[3] = 0; 2132 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2133 break; 2134 case 0x21: /* pws is present */ 2135 /* 2136 * This is for enclosures that cannot tell whether the 2137 * device is on or malfunctioning, but know that it is 2138 * present. Just fall through. 2139 */ 2140 /* FALLTHROUGH */ 2141 case 0x80: /* Unknown or Not Reportable Status */ 2142 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2143 ssc->ses_objmap[oid].encstat[3] = 0; 2144 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2145 break; 2146 default: 2147 SES_LOG(ssc, "unknown power supply %d status (0x%x)\n", 2148 i, sdata[r] & 0xff); 2149 break; 2150 } 2151 ssc->ses_objmap[oid++].svalid = 1; 2152 r++; 2153 } 2154 2155 /* 2156 * Skip over Slot SCSI IDs 2157 */ 2158 r += cc->Nslots; 2159 2160 /* 2161 * We always have doorlock status, no matter what, 2162 * but we only save the status if we have one. 2163 */ 2164 SAFT_BAIL(r, hiwater, sdata, buflen); 2165 if (cc->DoorLock) { 2166 /* 2167 * 0 = Door Locked 2168 * 1 = Door Unlocked, or no Lock Installed 2169 * 0x80 = Unknown or Not Reportable Status 2170 */ 2171 ssc->ses_objmap[oid].encstat[1] = 0; 2172 ssc->ses_objmap[oid].encstat[2] = 0; 2173 switch ((uint8_t)sdata[r]) { 2174 case 0: 2175 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2176 ssc->ses_objmap[oid].encstat[3] = 0; 2177 break; 2178 case 1: 2179 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2180 ssc->ses_objmap[oid].encstat[3] = 1; 2181 break; 2182 case 0x80: 2183 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNKNOWN; 2184 ssc->ses_objmap[oid].encstat[3] = 0; 2185 ssc->ses_encstat |= SES_ENCSTAT_INFO; 2186 break; 2187 default: 2188 ssc->ses_objmap[oid].encstat[0] = 2189 SES_OBJSTAT_UNSUPPORTED; 2190 SES_LOG(ssc, "unknown lock status 0x%x\n", 2191 sdata[r] & 0xff); 2192 break; 2193 } 2194 ssc->ses_objmap[oid++].svalid = 1; 2195 } 2196 r++; 2197 2198 /* 2199 * We always have speaker status, no matter what, 2200 * but we only save the status if we have one. 2201 */ 2202 SAFT_BAIL(r, hiwater, sdata, buflen); 2203 if (cc->Nspkrs) { 2204 ssc->ses_objmap[oid].encstat[1] = 0; 2205 ssc->ses_objmap[oid].encstat[2] = 0; 2206 if (sdata[r] == 1) { 2207 /* 2208 * We need to cache tone urgency indicators. 2209 * Someday. 2210 */ 2211 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NONCRIT; 2212 ssc->ses_objmap[oid].encstat[3] = 0x8; 2213 ssc->ses_encstat |= SES_ENCSTAT_NONCRITICAL; 2214 } else if (sdata[r] == 0) { 2215 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2216 ssc->ses_objmap[oid].encstat[3] = 0; 2217 } else { 2218 ssc->ses_objmap[oid].encstat[0] = 2219 SES_OBJSTAT_UNSUPPORTED; 2220 ssc->ses_objmap[oid].encstat[3] = 0; 2221 SES_LOG(ssc, "unknown spkr status 0x%x\n", 2222 sdata[r] & 0xff); 2223 } 2224 ssc->ses_objmap[oid++].svalid = 1; 2225 } 2226 r++; 2227 2228 for (i = 0; i < cc->Ntherm; i++) { 2229 SAFT_BAIL(r, hiwater, sdata, buflen); 2230 /* 2231 * Status is a range from -10 to 245 deg Celsius, 2232 * which we need to normalize to -20 to -245 according 2233 * to the latest SCSI spec, which makes little 2234 * sense since this would overflow an 8bit value. 2235 * Well, still, the base normalization is -20, 2236 * not -10, so we have to adjust. 2237 * 2238 * So what's over and under temperature? 2239 * Hmm- we'll state that 'normal' operating 2240 * is 10 to 40 deg Celsius. 2241 */ 2242 2243 /* 2244 * Actually.... All of the units that people out in the world 2245 * seem to have do not come even close to setting a value that 2246 * complies with this spec. 2247 * 2248 * The closest explanation I could find was in an 2249 * LSI-Logic manual, which seemed to indicate that 2250 * this value would be set by whatever the I2C code 2251 * would interpolate from the output of an LM75 2252 * temperature sensor. 2253 * 2254 * This means that it is impossible to use the actual 2255 * numeric value to predict anything. But we don't want 2256 * to lose the value. So, we'll propagate the *uncorrected* 2257 * value and set SES_OBJSTAT_NOTAVAIL. We'll depend on the 2258 * temperature flags for warnings. 2259 */ 2260 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_NOTAVAIL; 2261 ssc->ses_objmap[oid].encstat[1] = 0; 2262 ssc->ses_objmap[oid].encstat[2] = sdata[r]; 2263 ssc->ses_objmap[oid].encstat[3] = 0; 2264 ssc->ses_objmap[oid++].svalid = 1; 2265 r++; 2266 } 2267 2268 /* 2269 * Now, for "pseudo" thermometers, we have two bytes 2270 * of information in enclosure status- 16 bits. Actually, 2271 * the MSB is a single TEMP ALERT flag indicating whether 2272 * any other bits are set, but, thanks to fuzzy thinking, 2273 * in the SAF-TE spec, this can also be set even if no 2274 * other bits are set, thus making this really another 2275 * binary temperature sensor. 2276 */ 2277 2278 SAFT_BAIL(r, hiwater, sdata, buflen); 2279 tempflags = sdata[r++]; 2280 SAFT_BAIL(r, hiwater, sdata, buflen); 2281 tempflags |= (tempflags << 8) | sdata[r++]; 2282 2283 for (i = 0; i < NPSEUDO_THERM; i++) { 2284 ssc->ses_objmap[oid].encstat[1] = 0; 2285 if (tempflags & (1 << (NPSEUDO_THERM - i - 1))) { 2286 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_CRIT; 2287 ssc->ses_objmap[4].encstat[2] = 0xff; 2288 /* 2289 * Set 'over temperature' failure. 2290 */ 2291 ssc->ses_objmap[oid].encstat[3] = 8; 2292 ssc->ses_encstat |= SES_ENCSTAT_CRITICAL; 2293 } else { 2294 /* 2295 * We used to say 'not available' and synthesize a 2296 * nominal 30 deg (C)- that was wrong. Actually, 2297 * Just say 'OK', and use the reserved value of 2298 * zero. 2299 */ 2300 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2301 ssc->ses_objmap[oid].encstat[2] = 0; 2302 ssc->ses_objmap[oid].encstat[3] = 0; 2303 } 2304 ssc->ses_objmap[oid++].svalid = 1; 2305 } 2306 2307 /* 2308 * Get alarm status. 2309 */ 2310 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2311 ssc->ses_objmap[oid].encstat[3] = ssc->ses_objmap[oid].priv; 2312 ssc->ses_objmap[oid++].svalid = 1; 2313 2314 /* 2315 * Now get drive slot status 2316 */ 2317 cdb[2] = SAFTE_RD_RDDSTS; 2318 amt = buflen; 2319 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2320 if (err) { 2321 SES_FREE(sdata, buflen); 2322 return (err); 2323 } 2324 hiwater = buflen - amt; 2325 for (r = i = 0; i < cc->Nslots; i++, r += 4) { 2326 SAFT_BAIL(r+3, hiwater, sdata, buflen); 2327 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_UNSUPPORTED; 2328 ssc->ses_objmap[oid].encstat[1] = (uint8_t) i; 2329 ssc->ses_objmap[oid].encstat[2] = 0; 2330 ssc->ses_objmap[oid].encstat[3] = 0; 2331 status = sdata[r+3]; 2332 if ((status & 0x1) == 0) { /* no device */ 2333 ssc->ses_objmap[oid].encstat[0] = 2334 SES_OBJSTAT_NOTINSTALLED; 2335 } else { 2336 ssc->ses_objmap[oid].encstat[0] = SES_OBJSTAT_OK; 2337 } 2338 if (status & 0x2) { 2339 ssc->ses_objmap[oid].encstat[2] = 0x8; 2340 } 2341 if ((status & 0x4) == 0) { 2342 ssc->ses_objmap[oid].encstat[3] = 0x10; 2343 } 2344 ssc->ses_objmap[oid++].svalid = 1; 2345 } 2346 /* see comment below about sticky enclosure status */ 2347 ssc->ses_encstat |= ENCI_SVALID | oencstat; 2348 SES_FREE(sdata, buflen); 2349 return (0); 2350 } 2351 2352 static int 2353 set_objstat_sel(ses_softc_t *ssc, ses_objstat *obp, int slp) 2354 { 2355 int idx; 2356 encobj *ep; 2357 struct scfg *cc = ssc->ses_private; 2358 2359 if (cc == NULL) 2360 return (0); 2361 2362 idx = (int)obp->obj_id; 2363 ep = &ssc->ses_objmap[idx]; 2364 2365 switch (ep->enctype) { 2366 case SESTYP_DEVICE: 2367 if (obp->cstat[0] & SESCTL_PRDFAIL) { 2368 ep->priv |= 0x40; 2369 } 2370 /* SESCTL_RSTSWAP has no correspondence in SAF-TE */ 2371 if (obp->cstat[0] & SESCTL_DISABLE) { 2372 ep->priv |= 0x80; 2373 /* 2374 * Hmm. Try to set the 'No Drive' flag. 2375 * Maybe that will count as a 'disable'. 2376 */ 2377 } 2378 if (ep->priv & 0xc6) { 2379 ep->priv &= ~0x1; 2380 } else { 2381 ep->priv |= 0x1; /* no errors */ 2382 } 2383 wrslot_stat(ssc, slp); 2384 break; 2385 case SESTYP_POWER: 2386 /* 2387 * Okay- the only one that makes sense here is to 2388 * do the 'disable' for a power supply. 2389 */ 2390 if (obp->cstat[0] & SESCTL_DISABLE) { 2391 wrbuf16(ssc, SAFTE_WT_ACTPWS, 2392 idx - cc->pwroff, 0, 0, slp); 2393 } 2394 break; 2395 case SESTYP_FAN: 2396 /* 2397 * Okay- the only one that makes sense here is to 2398 * set fan speed to zero on disable. 2399 */ 2400 if (obp->cstat[0] & SESCTL_DISABLE) { 2401 /* remember- fans are the first items, so idx works */ 2402 wrbuf16(ssc, SAFTE_WT_FANSPD, idx, 0, 0, slp); 2403 } 2404 break; 2405 case SESTYP_DOORLOCK: 2406 /* 2407 * Well, we can 'disable' the lock. 2408 */ 2409 if (obp->cstat[0] & SESCTL_DISABLE) { 2410 cc->flag2 &= ~SAFT_FLG2_LOCKDOOR; 2411 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2412 cc->flag2, 0, slp); 2413 } 2414 break; 2415 case SESTYP_ALARM: 2416 /* 2417 * Well, we can 'disable' the alarm. 2418 */ 2419 if (obp->cstat[0] & SESCTL_DISABLE) { 2420 cc->flag2 &= ~SAFT_FLG1_ALARM; 2421 ep->priv |= 0x40; /* Muted */ 2422 wrbuf16(ssc, SAFTE_WT_GLOBAL, cc->flag1, 2423 cc->flag2, 0, slp); 2424 } 2425 break; 2426 default: 2427 break; 2428 } 2429 ep->svalid = 0; 2430 return (0); 2431 } 2432 2433 /* 2434 * This function handles all of the 16 byte WRITE BUFFER commands. 2435 */ 2436 static int 2437 wrbuf16(ses_softc_t *ssc, uint8_t op, uint8_t b1, uint8_t b2, 2438 uint8_t b3, int slp) 2439 { 2440 int err, amt; 2441 char *sdata; 2442 struct scfg *cc = ssc->ses_private; 2443 static char cdb[10] = { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, 16, 0 }; 2444 2445 if (cc == NULL) 2446 return (0); 2447 2448 sdata = SES_MALLOC(16); 2449 if (sdata == NULL) 2450 return (ENOMEM); 2451 2452 SES_DLOG(ssc, "saf_wrbuf16 %x %x %x %x\n", op, b1, b2, b3); 2453 2454 sdata[0] = op; 2455 sdata[1] = b1; 2456 sdata[2] = b2; 2457 sdata[3] = b3; 2458 MEMZERO(&sdata[4], 12); 2459 amt = -16; 2460 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2461 SES_FREE(sdata, 16); 2462 return (err); 2463 } 2464 2465 /* 2466 * This function updates the status byte for the device slot described. 2467 * 2468 * Since this is an optional SAF-TE command, there's no point in 2469 * returning an error. 2470 */ 2471 static void 2472 wrslot_stat(ses_softc_t *ssc, int slp) 2473 { 2474 int i, amt; 2475 encobj *ep; 2476 char cdb[10], *sdata; 2477 struct scfg *cc = ssc->ses_private; 2478 2479 if (cc == NULL) 2480 return; 2481 2482 SES_DLOG(ssc, "saf_wrslot\n"); 2483 cdb[0] = WRITE_BUFFER; 2484 cdb[1] = 1; 2485 cdb[2] = 0; 2486 cdb[3] = 0; 2487 cdb[4] = 0; 2488 cdb[5] = 0; 2489 cdb[6] = 0; 2490 cdb[7] = 0; 2491 cdb[8] = cc->Nslots * 3 + 1; 2492 cdb[9] = 0; 2493 2494 sdata = SES_MALLOC(cc->Nslots * 3 + 1); 2495 if (sdata == NULL) 2496 return; 2497 MEMZERO(sdata, cc->Nslots * 3 + 1); 2498 2499 sdata[0] = SAFTE_WT_DSTAT; 2500 for (i = 0; i < cc->Nslots; i++) { 2501 ep = &ssc->ses_objmap[cc->slotoff + i]; 2502 SES_DLOG(ssc, "saf_wrslot %d <- %x\n", i, ep->priv & 0xff); 2503 sdata[1 + (3 * i)] = ep->priv & 0xff; 2504 } 2505 amt = -(cc->Nslots * 3 + 1); 2506 ses_runcmd(ssc, cdb, 10, sdata, &amt); 2507 SES_FREE(sdata, cc->Nslots * 3 + 1); 2508 } 2509 2510 /* 2511 * This function issues the "PERFORM SLOT OPERATION" command. 2512 */ 2513 static int 2514 perf_slotop(ses_softc_t *ssc, uint8_t slot, uint8_t opflag, int slp) 2515 { 2516 int err, amt; 2517 char *sdata; 2518 struct scfg *cc = ssc->ses_private; 2519 static char cdb[10] = 2520 { WRITE_BUFFER, 1, 0, 0, 0, 0, 0, 0, SAFT_SCRATCH, 0 }; 2521 2522 if (cc == NULL) 2523 return (0); 2524 2525 sdata = SES_MALLOC(SAFT_SCRATCH); 2526 if (sdata == NULL) 2527 return (ENOMEM); 2528 MEMZERO(sdata, SAFT_SCRATCH); 2529 2530 sdata[0] = SAFTE_WT_SLTOP; 2531 sdata[1] = slot; 2532 sdata[2] = opflag; 2533 SES_DLOG(ssc, "saf_slotop slot %d op %x\n", slot, opflag); 2534 amt = -SAFT_SCRATCH; 2535 err = ses_runcmd(ssc, cdb, 10, sdata, &amt); 2536 SES_FREE(sdata, SAFT_SCRATCH); 2537 return (err); 2538 } 2539