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