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