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