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