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