1 /* $OpenBSD: ami.c,v 1.254 2020/07/24 12:43:31 krw Exp $ */ 2 3 /* 4 * Copyright (c) 2001 Michael Shalayeff 5 * Copyright (c) 2005 Marco Peereboom 6 * Copyright (c) 2006 David Gwynne 7 * All rights reserved. 8 * 9 * The SCSI emulation layer is derived from gdt(4) driver, 10 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 /* 34 * American Megatrends Inc. MegaRAID controllers driver 35 * 36 * This driver was made because these ppl and organizations 37 * donated hardware and provided documentation: 38 * 39 * - 428 model card 40 * John Kerbawy, Stephan Matis, Mark Stovall; 41 * 42 * - 467 and 475 model cards, docs 43 * American Megatrends Inc.; 44 * 45 * - uninterruptable electric power for cvs 46 * Theo de Raadt. 47 */ 48 49 #include "bio.h" 50 51 /* #define AMI_DEBUG */ 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/buf.h> 56 #include <sys/ioctl.h> 57 #include <sys/device.h> 58 #include <sys/kernel.h> 59 #include <sys/malloc.h> 60 #include <sys/rwlock.h> 61 #include <sys/pool.h> 62 #include <sys/sensors.h> 63 64 #include <machine/bus.h> 65 66 #include <scsi/scsi_all.h> 67 #include <scsi/scsi_disk.h> 68 #include <scsi/scsiconf.h> 69 70 #include <dev/biovar.h> 71 #include <dev/ic/amireg.h> 72 #include <dev/ic/amivar.h> 73 74 #ifdef AMI_DEBUG 75 #define AMI_DPRINTF(m,a) do { if (ami_debug & (m)) printf a; } while (0) 76 #define AMI_D_CMD 0x0001 77 #define AMI_D_INTR 0x0002 78 #define AMI_D_MISC 0x0004 79 #define AMI_D_DMA 0x0008 80 #define AMI_D_IOCTL 0x0010 81 int ami_debug = 0 82 /* | AMI_D_CMD */ 83 /* | AMI_D_INTR */ 84 /* | AMI_D_MISC */ 85 /* | AMI_D_DMA */ 86 /* | AMI_D_IOCTL */ 87 ; 88 #else 89 #define AMI_DPRINTF(m,a) /* m, a */ 90 #endif 91 92 struct cfdriver ami_cd = { 93 NULL, "ami", DV_DULL 94 }; 95 96 void ami_scsi_cmd(struct scsi_xfer *); 97 int ami_scsi_ioctl(struct scsi_link *, u_long, caddr_t, int); 98 99 struct scsi_adapter ami_switch = { 100 ami_scsi_cmd, NULL, NULL, NULL, ami_scsi_ioctl 101 }; 102 103 void ami_scsi_raw_cmd(struct scsi_xfer *); 104 105 struct scsi_adapter ami_raw_switch = { 106 ami_scsi_raw_cmd, NULL, NULL, NULL, NULL 107 }; 108 109 void * ami_get_ccb(void *); 110 void ami_put_ccb(void *, void *); 111 112 u_int32_t ami_read(struct ami_softc *, bus_size_t); 113 void ami_write(struct ami_softc *, bus_size_t, u_int32_t); 114 115 void ami_copyhds(struct ami_softc *, const u_int32_t *, 116 const u_int8_t *, const u_int8_t *); 117 struct ami_mem *ami_allocmem(struct ami_softc *, size_t); 118 void ami_freemem(struct ami_softc *, struct ami_mem *); 119 int ami_alloc_ccbs(struct ami_softc *, int); 120 121 int ami_poll(struct ami_softc *, struct ami_ccb *); 122 void ami_start(struct ami_softc *, struct ami_ccb *); 123 void ami_complete(struct ami_softc *, struct ami_ccb *, int); 124 void ami_runqueue_tick(void *); 125 void ami_runqueue(struct ami_softc *); 126 127 void ami_start_xs(struct ami_softc *sc, struct ami_ccb *, 128 struct scsi_xfer *); 129 void ami_done_xs(struct ami_softc *, struct ami_ccb *); 130 void ami_done_pt(struct ami_softc *, struct ami_ccb *); 131 void ami_done_flush(struct ami_softc *, struct ami_ccb *); 132 void ami_done_sysflush(struct ami_softc *, struct ami_ccb *); 133 134 void ami_done_dummy(struct ami_softc *, struct ami_ccb *); 135 void ami_done_ioctl(struct ami_softc *, struct ami_ccb *); 136 void ami_done_init(struct ami_softc *, struct ami_ccb *); 137 138 void ami_copy_internal_data(struct scsi_xfer *, void *, size_t); 139 140 int ami_load_ptmem(struct ami_softc*, struct ami_ccb *, 141 void *, size_t, int, int); 142 143 #if NBIO > 0 144 int ami_mgmt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t, 145 u_int8_t, size_t, void *); 146 int ami_drv_pt(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t *, 147 int, int, void *); 148 int ami_drv_readcap(struct ami_softc *, u_int8_t, u_int8_t, 149 daddr_t *); 150 int ami_drv_inq(struct ami_softc *, u_int8_t, u_int8_t, u_int8_t, 151 void *); 152 int ami_ioctl(struct device *, u_long, caddr_t); 153 int ami_ioctl_inq(struct ami_softc *, struct bioc_inq *); 154 int ami_vol(struct ami_softc *, struct bioc_vol *, 155 struct ami_big_diskarray *); 156 int ami_disk(struct ami_softc *, struct bioc_disk *, 157 struct ami_big_diskarray *); 158 int ami_ioctl_vol(struct ami_softc *, struct bioc_vol *); 159 int ami_ioctl_disk(struct ami_softc *, struct bioc_disk *); 160 int ami_ioctl_alarm(struct ami_softc *, struct bioc_alarm *); 161 int ami_ioctl_setstate(struct ami_softc *, struct bioc_setstate *); 162 163 #ifndef SMALL_KERNEL 164 int ami_create_sensors(struct ami_softc *); 165 void ami_refresh_sensors(void *); 166 #endif 167 #endif /* NBIO > 0 */ 168 169 #define DEVNAME(_s) ((_s)->sc_dev.dv_xname) 170 171 void * 172 ami_get_ccb(void *xsc) 173 { 174 struct ami_softc *sc = xsc; 175 struct ami_ccb *ccb; 176 177 mtx_enter(&sc->sc_ccb_freeq_mtx); 178 ccb = TAILQ_FIRST(&sc->sc_ccb_freeq); 179 if (ccb != NULL) { 180 TAILQ_REMOVE(&sc->sc_ccb_freeq, ccb, ccb_link); 181 ccb->ccb_state = AMI_CCB_READY; 182 } 183 mtx_leave(&sc->sc_ccb_freeq_mtx); 184 185 return (ccb); 186 } 187 188 void 189 ami_put_ccb(void *xsc, void *xccb) 190 { 191 struct ami_softc *sc = xsc; 192 struct ami_ccb *ccb = xccb; 193 194 ccb->ccb_state = AMI_CCB_FREE; 195 ccb->ccb_xs = NULL; 196 ccb->ccb_flags = 0; 197 ccb->ccb_done = NULL; 198 199 mtx_enter(&sc->sc_ccb_freeq_mtx); 200 TAILQ_INSERT_TAIL(&sc->sc_ccb_freeq, ccb, ccb_link); 201 mtx_leave(&sc->sc_ccb_freeq_mtx); 202 } 203 204 u_int32_t 205 ami_read(struct ami_softc *sc, bus_size_t r) 206 { 207 u_int32_t rv; 208 209 bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 210 BUS_SPACE_BARRIER_READ); 211 rv = bus_space_read_4(sc->sc_iot, sc->sc_ioh, r); 212 213 AMI_DPRINTF(AMI_D_CMD, ("ari 0x%lx 0x08%x ", r, rv)); 214 return (rv); 215 } 216 217 void 218 ami_write(struct ami_softc *sc, bus_size_t r, u_int32_t v) 219 { 220 AMI_DPRINTF(AMI_D_CMD, ("awo 0x%lx 0x%08x ", r, v)); 221 222 bus_space_write_4(sc->sc_iot, sc->sc_ioh, r, v); 223 bus_space_barrier(sc->sc_iot, sc->sc_ioh, r, 4, 224 BUS_SPACE_BARRIER_WRITE); 225 } 226 227 struct ami_mem * 228 ami_allocmem(struct ami_softc *sc, size_t size) 229 { 230 struct ami_mem *am; 231 int nsegs; 232 233 am = malloc(sizeof(struct ami_mem), M_DEVBUF, M_NOWAIT|M_ZERO); 234 if (am == NULL) 235 return (NULL); 236 237 am->am_size = size; 238 239 if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, 240 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &am->am_map) != 0) 241 goto amfree; 242 243 if (bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &am->am_seg, 1, 244 &nsegs, BUS_DMA_NOWAIT | BUS_DMA_ZERO) != 0) 245 goto destroy; 246 247 if (bus_dmamem_map(sc->sc_dmat, &am->am_seg, nsegs, size, &am->am_kva, 248 BUS_DMA_NOWAIT) != 0) 249 goto free; 250 251 if (bus_dmamap_load(sc->sc_dmat, am->am_map, am->am_kva, size, NULL, 252 BUS_DMA_NOWAIT) != 0) 253 goto unmap; 254 255 return (am); 256 257 unmap: 258 bus_dmamem_unmap(sc->sc_dmat, am->am_kva, size); 259 free: 260 bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1); 261 destroy: 262 bus_dmamap_destroy(sc->sc_dmat, am->am_map); 263 amfree: 264 free(am, M_DEVBUF, sizeof *am); 265 266 return (NULL); 267 } 268 269 void 270 ami_freemem(struct ami_softc *sc, struct ami_mem *am) 271 { 272 bus_dmamap_unload(sc->sc_dmat, am->am_map); 273 bus_dmamem_unmap(sc->sc_dmat, am->am_kva, am->am_size); 274 bus_dmamem_free(sc->sc_dmat, &am->am_seg, 1); 275 bus_dmamap_destroy(sc->sc_dmat, am->am_map); 276 free(am, M_DEVBUF, sizeof *am); 277 } 278 279 void 280 ami_copyhds(struct ami_softc *sc, const u_int32_t *sizes, 281 const u_int8_t *props, const u_int8_t *stats) 282 { 283 int i; 284 285 for (i = 0; i < sc->sc_nunits; i++) { 286 sc->sc_hdr[i].hd_present = 1; 287 sc->sc_hdr[i].hd_is_logdrv = 1; 288 sc->sc_hdr[i].hd_size = letoh32(sizes[i]); 289 sc->sc_hdr[i].hd_prop = props[i]; 290 sc->sc_hdr[i].hd_stat = stats[i]; 291 } 292 } 293 294 int 295 ami_alloc_ccbs(struct ami_softc *sc, int nccbs) 296 { 297 struct ami_ccb *ccb; 298 struct ami_ccbmem *ccbmem, *mem; 299 int i, error; 300 301 sc->sc_ccbs = mallocarray(nccbs, sizeof(struct ami_ccb), 302 M_DEVBUF, M_NOWAIT); 303 if (sc->sc_ccbs == NULL) { 304 printf(": unable to allocate ccbs\n"); 305 return (1); 306 } 307 308 sc->sc_ccbmem_am = ami_allocmem(sc, sizeof(struct ami_ccbmem) * nccbs); 309 if (sc->sc_ccbmem_am == NULL) { 310 printf(": unable to allocate ccb dmamem\n"); 311 goto free_ccbs; 312 } 313 ccbmem = AMIMEM_KVA(sc->sc_ccbmem_am); 314 315 TAILQ_INIT(&sc->sc_ccb_freeq); 316 mtx_init(&sc->sc_ccb_freeq_mtx, IPL_BIO); 317 TAILQ_INIT(&sc->sc_ccb_preq); 318 TAILQ_INIT(&sc->sc_ccb_runq); 319 timeout_set(&sc->sc_run_tmo, ami_runqueue_tick, sc); 320 321 scsi_iopool_init(&sc->sc_iopool, sc, ami_get_ccb, ami_put_ccb); 322 323 for (i = 0; i < nccbs; i++) { 324 ccb = &sc->sc_ccbs[i]; 325 mem = &ccbmem[i]; 326 327 error = bus_dmamap_create(sc->sc_dmat, AMI_MAXFER, 328 AMI_MAXOFFSETS, AMI_MAXFER, 0, 329 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap); 330 if (error) { 331 printf(": cannot create ccb dmamap (%d)\n", error); 332 goto free_list; 333 } 334 335 ccb->ccb_sc = sc; 336 337 ccb->ccb_cmd.acc_id = i + 1; 338 ccb->ccb_offset = sizeof(struct ami_ccbmem) * i; 339 340 ccb->ccb_pt = &mem->cd_pt; 341 ccb->ccb_ptpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) + 342 ccb->ccb_offset); 343 344 ccb->ccb_sglist = mem->cd_sg; 345 ccb->ccb_sglistpa = htole32(AMIMEM_DVA(sc->sc_ccbmem_am) + 346 ccb->ccb_offset + sizeof(struct ami_passthrough)); 347 348 /* override last command for management */ 349 if (i == nccbs - 1) { 350 ccb->ccb_cmd.acc_id = 0xfe; 351 sc->sc_mgmtccb = ccb; 352 } else { 353 ami_put_ccb(sc, ccb); 354 } 355 } 356 357 return (0); 358 359 free_list: 360 while ((ccb = ami_get_ccb(sc)) != NULL) 361 bus_dmamap_destroy(sc->sc_dmat, ccb->ccb_dmamap); 362 363 ami_freemem(sc, sc->sc_ccbmem_am); 364 free_ccbs: 365 free(sc->sc_ccbs, M_DEVBUF, 0); 366 367 return (1); 368 } 369 370 int 371 ami_attach(struct ami_softc *sc) 372 { 373 struct scsibus_attach_args saa; 374 struct ami_rawsoftc *rsc; 375 struct ami_ccb iccb; 376 struct ami_iocmd *cmd; 377 struct ami_mem *am; 378 struct ami_inquiry *inq; 379 struct ami_fc_einquiry *einq; 380 struct ami_fc_prodinfo *pi; 381 const char *p; 382 paddr_t pa; 383 384 mtx_init(&sc->sc_cmd_mtx, IPL_BIO); 385 386 am = ami_allocmem(sc, NBPG); 387 if (am == NULL) { 388 printf(": unable to allocate init data\n"); 389 return (1); 390 } 391 pa = htole32(AMIMEM_DVA(am)); 392 393 sc->sc_mbox_am = ami_allocmem(sc, sizeof(struct ami_iocmd)); 394 if (sc->sc_mbox_am == NULL) { 395 printf(": unable to allocate mbox\n"); 396 goto free_idata; 397 } 398 sc->sc_mbox = (volatile struct ami_iocmd *)AMIMEM_KVA(sc->sc_mbox_am); 399 sc->sc_mbox_pa = htole32(AMIMEM_DVA(sc->sc_mbox_am)); 400 AMI_DPRINTF(AMI_D_CMD, ("mbox=%p ", sc->sc_mbox)); 401 AMI_DPRINTF(AMI_D_CMD, ("mbox_pa=0x%llx ", (long long)sc->sc_mbox_pa)); 402 403 /* create a spartan ccb for use with ami_poll */ 404 bzero(&iccb, sizeof(iccb)); 405 iccb.ccb_sc = sc; 406 iccb.ccb_done = ami_done_init; 407 cmd = &iccb.ccb_cmd; 408 409 (sc->sc_init)(sc); 410 411 /* try FC inquiry first */ 412 cmd->acc_cmd = AMI_FCOP; 413 cmd->acc_io.aio_channel = AMI_FC_EINQ3; 414 cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL; 415 cmd->acc_io.aio_data = pa; 416 if (ami_poll(sc, &iccb) == 0) { 417 einq = AMIMEM_KVA(am); 418 pi = AMIMEM_KVA(am); 419 420 sc->sc_nunits = einq->ain_nlogdrv; 421 sc->sc_drvinscnt = einq->ain_drvinscnt + 1; /* force scan */ 422 ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop, 423 einq->ain_ldstat); 424 425 cmd->acc_cmd = AMI_FCOP; 426 cmd->acc_io.aio_channel = AMI_FC_PRODINF; 427 cmd->acc_io.aio_param = 0; 428 cmd->acc_io.aio_data = pa; 429 if (ami_poll(sc, &iccb) == 0) { 430 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 431 432 bcopy (pi->api_fwver, sc->sc_fwver, 16); 433 sc->sc_fwver[15] = '\0'; 434 bcopy (pi->api_biosver, sc->sc_biosver, 16); 435 sc->sc_biosver[15] = '\0'; 436 sc->sc_channels = pi->api_channels; 437 sc->sc_targets = pi->api_fcloops; 438 sc->sc_memory = letoh16(pi->api_ramsize); 439 sc->sc_maxcmds = pi->api_maxcmd; 440 p = "FC loop"; 441 } 442 } 443 444 if (sc->sc_maxunits == 0) { 445 inq = AMIMEM_KVA(am); 446 447 cmd->acc_cmd = AMI_EINQUIRY; 448 cmd->acc_io.aio_channel = 0; 449 cmd->acc_io.aio_param = 0; 450 cmd->acc_io.aio_data = pa; 451 if (ami_poll(sc, &iccb) != 0) { 452 cmd->acc_cmd = AMI_INQUIRY; 453 cmd->acc_io.aio_channel = 0; 454 cmd->acc_io.aio_param = 0; 455 cmd->acc_io.aio_data = pa; 456 if (ami_poll(sc, &iccb) != 0) { 457 printf(": cannot do inquiry\n"); 458 goto free_mbox; 459 } 460 } 461 462 sc->sc_maxunits = AMI_MAX_LDRIVES; 463 sc->sc_nunits = inq->ain_nlogdrv; 464 ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop, 465 inq->ain_ldstat); 466 467 bcopy (inq->ain_fwver, sc->sc_fwver, 4); 468 sc->sc_fwver[4] = '\0'; 469 bcopy (inq->ain_biosver, sc->sc_biosver, 4); 470 sc->sc_biosver[4] = '\0'; 471 sc->sc_channels = inq->ain_channels; 472 sc->sc_targets = inq->ain_targets; 473 sc->sc_memory = inq->ain_ramsize; 474 sc->sc_maxcmds = inq->ain_maxcmd; 475 sc->sc_drvinscnt = inq->ain_drvinscnt + 1; /* force scan */ 476 p = "target"; 477 } 478 479 if (sc->sc_flags & AMI_BROKEN) { 480 sc->sc_maxcmds = 1; 481 sc->sc_maxunits = 1; 482 } else { 483 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 484 if (sc->sc_maxcmds > AMI_MAXCMDS) 485 sc->sc_maxcmds = AMI_MAXCMDS; 486 /* 487 * Reserve ccb's for ioctl's and raw commands to 488 * processors/enclosures by lowering the number of 489 * openings available for logical units. 490 */ 491 sc->sc_maxcmds -= AMI_MAXIOCTLCMDS + AMI_MAXPROCS * 492 AMI_MAXRAWCMDS * sc->sc_channels; 493 } 494 495 if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) { 496 /* error already printed */ 497 goto free_mbox; 498 } 499 500 ami_freemem(sc, am); 501 502 /* hack for hp netraid version encoding */ 503 if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' && 504 sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' && 505 'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' && 506 sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') { 507 508 snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d", 509 sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]); 510 snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d", 511 sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]); 512 } 513 514 /* TODO: fetch & print cache strategy */ 515 /* TODO: fetch & print scsi and raid info */ 516 517 #ifdef AMI_DEBUG 518 printf(", FW %s, BIOS v%s, %dMB RAM\n" 519 "%s: %d channels, %d %ss, %d logical drives, " 520 "max commands %d, quirks: %04x\n", 521 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 522 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits, 523 sc->sc_maxcmds, sc->sc_flags); 524 #else 525 printf(", FW %s, BIOS v%s, %dMB RAM\n" 526 "%s: %d channels, %d %ss, %d logical drives\n", 527 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 528 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits); 529 #endif /* AMI_DEBUG */ 530 531 if (sc->sc_flags & AMI_BROKEN && sc->sc_nunits > 1) 532 printf("%s: firmware buggy, limiting access to first logical " 533 "disk\n", DEVNAME(sc)); 534 535 /* lock around ioctl requests */ 536 rw_init(&sc->sc_lock, NULL); 537 538 saa.saa_adapter_softc = sc; 539 saa.saa_adapter = &ami_switch; 540 saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET; 541 saa.saa_adapter_buswidth = sc->sc_maxunits; 542 saa.saa_luns = 8; 543 saa.saa_openings = sc->sc_maxcmds; 544 saa.saa_pool = &sc->sc_iopool; 545 saa.saa_quirks = saa.saa_flags = 0; 546 saa.saa_wwpn = saa.saa_wwnn = 0; 547 548 sc->sc_scsibus = (struct scsibus_softc *)config_found(&sc->sc_dev, &saa, 549 scsiprint); 550 551 /* can't do bioctls, sensors, or pass-through on broken devices */ 552 if (sc->sc_flags & AMI_BROKEN) 553 return (0); 554 555 #if NBIO > 0 556 if (bio_register(&sc->sc_dev, ami_ioctl) != 0) 557 printf("%s: controller registration failed\n", DEVNAME(sc)); 558 else 559 sc->sc_ioctl = ami_ioctl; 560 561 #ifndef SMALL_KERNEL 562 if (ami_create_sensors(sc) != 0) 563 printf("%s: unable to create sensors\n", DEVNAME(sc)); 564 #endif 565 #endif 566 567 rsc = mallocarray(sc->sc_channels, sizeof(struct ami_rawsoftc), 568 M_DEVBUF, M_NOWAIT|M_ZERO); 569 if (!rsc) { 570 printf("%s: no memory for raw interface\n", DEVNAME(sc)); 571 return (0); 572 } 573 574 for (sc->sc_rawsoftcs = rsc; 575 rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) { 576 577 struct scsibus_softc *ptbus; 578 struct scsi_link *proclink; 579 struct device *procdev; 580 581 rsc->sc_softc = sc; 582 rsc->sc_channel = rsc - sc->sc_rawsoftcs; 583 rsc->sc_proctarget = -1; 584 585 /* TODO fetch adapter_target from the controller */ 586 587 saa.saa_adapter_softc = rsc; 588 saa.saa_adapter = &ami_raw_switch; 589 saa.saa_adapter_target = SDEV_NO_ADAPTER_TARGET; 590 saa.saa_adapter_buswidth = 16; 591 saa.saa_luns = 8; 592 saa.saa_openings = sc->sc_maxcmds; 593 saa.saa_pool = &sc->sc_iopool; 594 saa.saa_quirks = saa.saa_flags = 0; 595 saa.saa_wwpn = saa.saa_wwnn = 0; 596 597 ptbus = (struct scsibus_softc *)config_found(&sc->sc_dev, 598 &saa, scsiprint); 599 600 if (ptbus == NULL || rsc->sc_proctarget == -1) 601 continue; 602 603 proclink = scsi_get_link(ptbus, rsc->sc_proctarget, 0); 604 if (proclink == NULL) 605 continue; 606 607 procdev = proclink->device_softc; 608 strlcpy(rsc->sc_procdev, procdev->dv_xname, 609 sizeof(rsc->sc_procdev)); 610 } 611 612 return (0); 613 614 free_mbox: 615 ami_freemem(sc, sc->sc_mbox_am); 616 free_idata: 617 ami_freemem(sc, am); 618 619 return (1); 620 } 621 622 int 623 ami_quartz_init(struct ami_softc *sc) 624 { 625 ami_write(sc, AMI_QIDB, 0); 626 627 return (0); 628 } 629 630 int 631 ami_quartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 632 { 633 if (sc->sc_mbox->acc_busy) { 634 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 635 return (EBUSY); 636 } 637 638 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 639 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 640 sizeof(struct ami_iocmd), BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 641 642 sc->sc_mbox->acc_busy = 1; 643 sc->sc_mbox->acc_poll = 0; 644 sc->sc_mbox->acc_ack = 0; 645 646 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 647 648 return (0); 649 } 650 651 int 652 ami_quartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 653 { 654 u_int32_t i, n; 655 u_int8_t nstat, status; 656 u_int8_t completed[AMI_MAXSTATACK]; 657 658 if (ami_read(sc, AMI_QODB) != AMI_QODB_READY) 659 return (0); /* nothing to do */ 660 661 ami_write(sc, AMI_QODB, AMI_QODB_READY); 662 663 /* 664 * The following sequence is not supposed to have a timeout clause 665 * since the firmware has a "guarantee" that all commands will 666 * complete. The choice is either panic or hoping for a miracle 667 * and that the IOs will complete much later. 668 */ 669 i = 0; 670 while ((nstat = sc->sc_mbox->acc_nstat) == 0xff) { 671 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 672 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTREAD); 673 delay(1); 674 if (i++ > 1000000) 675 return (0); /* nothing to do */ 676 } 677 sc->sc_mbox->acc_nstat = 0xff; 678 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 679 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 680 681 /* wait until fw wrote out all completions */ 682 i = 0; 683 AMI_DPRINTF(AMI_D_CMD, ("aqd %d ", nstat)); 684 for (n = 0; n < nstat; n++) { 685 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 686 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 687 while ((completed[n] = sc->sc_mbox->acc_cmplidl[n]) == 0xff) { 688 delay(1); 689 if (i++ > 1000000) 690 return (0); /* nothing to do */ 691 } 692 sc->sc_mbox->acc_cmplidl[n] = 0xff; 693 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 694 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 695 } 696 697 /* this should never happen, someone screwed up the completion status */ 698 if ((status = sc->sc_mbox->acc_status) == 0xff) 699 panic("%s: status 0xff from the firmware", DEVNAME(sc)); 700 701 sc->sc_mbox->acc_status = 0xff; 702 703 /* copy mailbox to temporary one and fixup other changed values */ 704 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 705 BUS_DMASYNC_POSTWRITE); 706 memcpy(mbox, (struct ami_iocmd *)sc->sc_mbox, 16); 707 mbox->acc_nstat = nstat; 708 mbox->acc_status = status; 709 for (n = 0; n < nstat; n++) 710 mbox->acc_cmplidl[n] = completed[n]; 711 712 /* ack interrupt */ 713 ami_write(sc, AMI_QIDB, AMI_QIDB_ACK); 714 715 return (1); /* ready to complete all IOs in acc_cmplidl */ 716 } 717 718 int 719 ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd) 720 { 721 /* struct scsi_xfer *xs = ccb->ccb_xs; */ 722 u_int32_t i; 723 u_int8_t status; 724 725 splassert(IPL_BIO); 726 727 if (sc->sc_dis_poll) 728 return (-1); /* fail */ 729 730 i = 0; 731 while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) { 732 delay(1); 733 i++; 734 } 735 if (sc->sc_mbox->acc_busy) { 736 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 737 return (-1); 738 } 739 740 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 741 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 742 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 743 744 sc->sc_mbox->acc_id = 0xfe; 745 sc->sc_mbox->acc_busy = 1; 746 sc->sc_mbox->acc_poll = 0; 747 sc->sc_mbox->acc_ack = 0; 748 sc->sc_mbox->acc_nstat = 0xff; 749 sc->sc_mbox->acc_status = 0xff; 750 751 /* send command to firmware */ 752 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 753 754 i = 0; 755 while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) { 756 delay(1); 757 i++; 758 } 759 if (i >= AMI_MAX_POLLWAIT) { 760 printf("%s: command not accepted, polling disabled\n", 761 DEVNAME(sc)); 762 sc->sc_dis_poll = 1; 763 return (-1); 764 } 765 766 /* poll firmware */ 767 i = 0; 768 while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) { 769 delay(1); 770 i++; 771 } 772 if (i >= AMI_MAX_POLLWAIT) { 773 printf("%s: firmware didn't reply, polling disabled\n", 774 DEVNAME(sc)); 775 sc->sc_dis_poll = 1; 776 return (-1); 777 } 778 779 /* ack */ 780 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK)); 781 782 i = 0; 783 while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) && 784 (i < AMI_MAX_POLLWAIT)) { 785 delay(1); 786 i++; 787 } 788 if (i >= AMI_MAX_POLLWAIT) { 789 printf("%s: firmware didn't ack the ack, polling disabled\n", 790 DEVNAME(sc)); 791 sc->sc_dis_poll = 1; 792 return (-1); 793 } 794 795 sc->sc_mbox->acc_poll = 0; 796 sc->sc_mbox->acc_ack = 0x77; 797 status = sc->sc_mbox->acc_status; 798 sc->sc_mbox->acc_nstat = 0xff; 799 sc->sc_mbox->acc_status = 0xff; 800 801 for (i = 0; i < AMI_MAXSTATACK; i++) 802 sc->sc_mbox->acc_cmplidl[i] = 0xff; 803 804 return (status); 805 } 806 807 int 808 ami_schwartz_init(struct ami_softc *sc) 809 { 810 u_int32_t a = (u_int32_t)sc->sc_mbox_pa; 811 812 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AMI_SMBADDR, a); 813 /* XXX 40bit address ??? */ 814 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SMBENA, 0); 815 816 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 817 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM, AMI_SEIM_ENA | 818 bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM)); 819 820 return (0); 821 } 822 823 int 824 ami_schwartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 825 { 826 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 827 AMI_SMBST_BUSY) { 828 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 829 return (EBUSY); 830 } 831 832 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 833 sc->sc_mbox->acc_busy = 1; 834 sc->sc_mbox->acc_poll = 0; 835 sc->sc_mbox->acc_ack = 0; 836 837 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 838 return (0); 839 } 840 841 int 842 ami_schwartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 843 { 844 u_int8_t stat; 845 846 #if 0 847 /* do not scramble the busy mailbox */ 848 if (sc->sc_mbox->acc_busy) 849 return (0); 850 #endif 851 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 852 AMI_SMBST_BUSY) 853 return (0); 854 855 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 856 if (stat & AMI_ISTAT_PEND) { 857 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, stat); 858 859 *mbox = *sc->sc_mbox; 860 AMI_DPRINTF(AMI_D_CMD, ("asd %d ", mbox->acc_nstat)); 861 862 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, 863 AMI_SCMD_ACK); 864 865 return (1); 866 } 867 868 return (0); 869 } 870 871 int 872 ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox) 873 { 874 u_int8_t status; 875 u_int32_t i; 876 int rv; 877 878 splassert(IPL_BIO); 879 880 if (sc->sc_dis_poll) 881 return (-1); /* fail */ 882 883 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 884 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 885 AMI_SMBST_BUSY)) 886 break; 887 delay(1); 888 } 889 if (i >= AMI_MAX_POLLWAIT) { 890 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 891 return (-1); 892 } 893 894 memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16); 895 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 896 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 897 898 sc->sc_mbox->acc_busy = 1; 899 sc->sc_mbox->acc_poll = 0; 900 sc->sc_mbox->acc_ack = 0; 901 /* send command to firmware */ 902 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 903 904 /* wait until no longer busy */ 905 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 906 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 907 AMI_SMBST_BUSY)) 908 break; 909 delay(1); 910 } 911 if (i >= AMI_MAX_POLLWAIT) { 912 printf("%s: command not accepted, polling disabled\n", 913 DEVNAME(sc)); 914 sc->sc_dis_poll = 1; 915 return (-1); 916 } 917 918 /* wait for interrupt bit */ 919 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 920 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 921 if (status & AMI_ISTAT_PEND) 922 break; 923 delay(1); 924 } 925 if (i >= AMI_MAX_POLLWAIT) { 926 printf("%s: interrupt didn't arrive, polling disabled\n", 927 DEVNAME(sc)); 928 sc->sc_dis_poll = 1; 929 return (-1); 930 } 931 932 /* write ststus back to firmware */ 933 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, status); 934 935 /* copy mailbox and status back */ 936 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 937 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 938 *mbox = *sc->sc_mbox; 939 rv = sc->sc_mbox->acc_status; 940 941 /* ack interrupt */ 942 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 943 944 return (rv); 945 } 946 947 void 948 ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs) 949 { 950 if (xs->flags & SCSI_POLL) 951 ami_complete(sc, ccb, xs->timeout); 952 else 953 ami_start(sc, ccb); 954 } 955 956 void 957 ami_start(struct ami_softc *sc, struct ami_ccb *ccb) 958 { 959 mtx_enter(&sc->sc_cmd_mtx); 960 ccb->ccb_state = AMI_CCB_PREQUEUED; 961 TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link); 962 mtx_leave(&sc->sc_cmd_mtx); 963 964 ami_runqueue(sc); 965 } 966 967 void 968 ami_runqueue_tick(void *arg) 969 { 970 ami_runqueue(arg); 971 } 972 973 void 974 ami_runqueue(struct ami_softc *sc) 975 { 976 struct ami_ccb *ccb; 977 int add = 0; 978 979 mtx_enter(&sc->sc_cmd_mtx); 980 if (!sc->sc_drainio) { 981 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) { 982 if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) { 983 add = 1; 984 break; 985 } 986 987 TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); 988 ccb->ccb_state = AMI_CCB_QUEUED; 989 TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); 990 } 991 } 992 mtx_leave(&sc->sc_cmd_mtx); 993 994 if (add) 995 timeout_add(&sc->sc_run_tmo, 1); 996 } 997 998 int 999 ami_poll(struct ami_softc *sc, struct ami_ccb *ccb) 1000 { 1001 int error; 1002 1003 mtx_enter(&sc->sc_cmd_mtx); 1004 error = sc->sc_poll(sc, &ccb->ccb_cmd); 1005 if (error == -1) 1006 ccb->ccb_flags |= AMI_CCB_F_ERR; 1007 mtx_leave(&sc->sc_cmd_mtx); 1008 1009 ccb->ccb_done(sc, ccb); 1010 1011 return (error); 1012 } 1013 1014 void 1015 ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout) 1016 { 1017 void (*done)(struct ami_softc *, struct ami_ccb *); 1018 int ready; 1019 int i = 0; 1020 int s; 1021 1022 done = ccb->ccb_done; 1023 ccb->ccb_done = ami_done_dummy; 1024 1025 /* 1026 * since exec will return if the mbox is busy we have to busy wait 1027 * ourselves. once its in, jam it into the runq. 1028 */ 1029 mtx_enter(&sc->sc_cmd_mtx); 1030 while (i < AMI_MAX_BUSYWAIT) { 1031 if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) { 1032 ccb->ccb_state = AMI_CCB_QUEUED; 1033 TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); 1034 break; 1035 } 1036 DELAY(1000); 1037 i++; 1038 } 1039 ready = (ccb->ccb_state == AMI_CCB_QUEUED); 1040 mtx_leave(&sc->sc_cmd_mtx); 1041 1042 if (!ready) { 1043 ccb->ccb_flags |= AMI_CCB_F_ERR; 1044 ccb->ccb_state = AMI_CCB_READY; 1045 goto done; 1046 } 1047 1048 /* 1049 * Override timeout for PERC3. The first command triggers a chip 1050 * reset on the QL12160 chip which causes the firmware to reload. 1051 * 30000 is slightly less than double of how long it takes for the 1052 * firmware to be up again. After the first two commands the 1053 * timeouts are as expected. 1054 */ 1055 timeout = MAX(30000, timeout); /* timeout */ 1056 1057 while (ccb->ccb_state == AMI_CCB_QUEUED) { 1058 s = splbio(); /* interrupt handlers are called at their IPL */ 1059 ready = ami_intr(sc); 1060 splx(s); 1061 1062 if (ready == 0) { 1063 if (timeout-- == 0) { 1064 /* XXX */ 1065 printf("%s: timeout\n", DEVNAME(sc)); 1066 return; 1067 } 1068 1069 delay(1000); 1070 continue; 1071 } 1072 } 1073 1074 done: 1075 done(sc, ccb); 1076 } 1077 1078 void 1079 ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb) 1080 { 1081 struct scsi_xfer *xs = ccb->ccb_xs; 1082 struct scsi_link *link = xs->sc_link; 1083 struct ami_rawsoftc *rsc = link->bus->sb_adapter_softc; 1084 u_int8_t target = link->target, type; 1085 1086 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1087 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1088 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1089 1090 if (xs->data != NULL) { 1091 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1092 ccb->ccb_dmamap->dm_mapsize, 1093 (xs->flags & SCSI_DATA_IN) ? 1094 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1095 1096 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1097 } 1098 1099 xs->resid = 0; 1100 1101 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1102 xs->error = XS_DRIVER_STUFFUP; 1103 else if (ccb->ccb_status != 0x00) 1104 xs->error = XS_DRIVER_STUFFUP; 1105 else if (xs->flags & SCSI_POLL && xs->cmd->opcode == INQUIRY) { 1106 type = ((struct scsi_inquiry_data *)xs->data)->device & 1107 SID_TYPE; 1108 if (!(type == T_PROCESSOR || type == T_ENCLOSURE)) 1109 xs->error = XS_DRIVER_STUFFUP; 1110 else 1111 rsc->sc_proctarget = target; 1112 } 1113 1114 scsi_done(xs); 1115 } 1116 1117 void 1118 ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb) 1119 { 1120 struct scsi_xfer *xs = ccb->ccb_xs; 1121 1122 if (xs->data != NULL) { 1123 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1124 ccb->ccb_dmamap->dm_mapsize, 1125 (xs->flags & SCSI_DATA_IN) ? 1126 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1127 1128 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1129 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1130 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1131 1132 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1133 } 1134 1135 xs->resid = 0; 1136 1137 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1138 xs->error = XS_DRIVER_STUFFUP; 1139 1140 scsi_done(xs); 1141 } 1142 1143 void 1144 ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb) 1145 { 1146 struct scsi_xfer *xs = ccb->ccb_xs; 1147 struct ami_iocmd *cmd = &ccb->ccb_cmd; 1148 1149 if (ccb->ccb_flags & AMI_CCB_F_ERR) { 1150 xs->error = XS_DRIVER_STUFFUP; 1151 xs->resid = 0; 1152 1153 scsi_done(xs); 1154 return; 1155 } 1156 1157 /* reuse the ccb for the sysflush command */ 1158 ccb->ccb_done = ami_done_sysflush; 1159 cmd->acc_cmd = AMI_SYSFLUSH; 1160 1161 ami_start_xs(sc, ccb, xs); 1162 } 1163 1164 void 1165 ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb) 1166 { 1167 struct scsi_xfer *xs = ccb->ccb_xs; 1168 1169 xs->resid = 0; 1170 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1171 xs->error = XS_DRIVER_STUFFUP; 1172 1173 scsi_done(xs); 1174 } 1175 1176 void 1177 ami_done_dummy(struct ami_softc *sc, struct ami_ccb *ccb) 1178 { 1179 } 1180 1181 void 1182 ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb) 1183 { 1184 wakeup(ccb); 1185 } 1186 1187 void 1188 ami_done_init(struct ami_softc *sc, struct ami_ccb *ccb) 1189 { 1190 /* the ccb is going to be reused, so do nothing with it */ 1191 } 1192 1193 void 1194 ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size) 1195 { 1196 size_t copy_cnt; 1197 1198 AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data ")); 1199 1200 if (!xs->datalen) 1201 printf("uio move not yet supported\n"); 1202 else { 1203 copy_cnt = MIN(size, xs->datalen); 1204 bcopy(v, xs->data, copy_cnt); 1205 } 1206 } 1207 1208 void 1209 ami_scsi_raw_cmd(struct scsi_xfer *xs) 1210 { 1211 struct scsi_link *link = xs->sc_link; 1212 struct ami_rawsoftc *rsc = link->bus->sb_adapter_softc; 1213 struct ami_softc *sc = rsc->sc_softc; 1214 u_int8_t channel = rsc->sc_channel, target = link->target; 1215 struct ami_ccb *ccb; 1216 1217 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd ")); 1218 1219 if (xs->cmdlen > AMI_MAX_CDB) { 1220 AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs)); 1221 bzero(&xs->sense, sizeof(xs->sense)); 1222 xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT; 1223 xs->sense.flags = SKEY_ILLEGAL_REQUEST; 1224 xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */ 1225 xs->error = XS_SENSE; 1226 scsi_done(xs); 1227 return; 1228 } 1229 1230 xs->error = XS_NOERROR; 1231 1232 ccb = xs->io; 1233 1234 memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough)); 1235 1236 ccb->ccb_xs = xs; 1237 ccb->ccb_done = ami_done_pt; 1238 1239 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1240 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1241 1242 ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0); 1243 ccb->ccb_pt->apt_channel = channel; 1244 ccb->ccb_pt->apt_target = target; 1245 bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB); 1246 ccb->ccb_pt->apt_ncdb = xs->cmdlen; 1247 ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE; 1248 ccb->ccb_pt->apt_datalen = xs->datalen; 1249 ccb->ccb_pt->apt_data = 0; 1250 1251 if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen, 1252 xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) { 1253 xs->error = XS_DRIVER_STUFFUP; 1254 scsi_done(xs); 1255 return; 1256 } 1257 1258 ami_start_xs(sc, ccb, xs); 1259 } 1260 1261 int 1262 ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data, 1263 size_t len, int read, int nowait) 1264 { 1265 bus_dmamap_t dmap = ccb->ccb_dmamap; 1266 bus_dma_segment_t *sgd; 1267 int error, i; 1268 1269 if (data != NULL) { 1270 error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL, 1271 nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1272 if (error) { 1273 if (error == EFBIG) 1274 printf("more than %d dma segs\n", 1275 AMI_MAXOFFSETS); 1276 else 1277 printf("error %d loading dma map\n", error); 1278 1279 return (1); 1280 } 1281 1282 sgd = dmap->dm_segs; 1283 if (dmap->dm_nsegs > 1) { 1284 struct ami_sgent *sgl = ccb->ccb_sglist; 1285 1286 ccb->ccb_pt->apt_nsge = dmap->dm_nsegs; 1287 ccb->ccb_pt->apt_data = ccb->ccb_sglistpa; 1288 1289 for (i = 0; i < dmap->dm_nsegs; i++) { 1290 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1291 sgl[i].asg_len = htole32(sgd[i].ds_len); 1292 } 1293 } else { 1294 ccb->ccb_pt->apt_nsge = 0; 1295 ccb->ccb_pt->apt_data = htole32(sgd->ds_addr); 1296 } 1297 1298 bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, 1299 read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1300 } 1301 1302 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1303 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1304 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1305 1306 return (0); 1307 } 1308 1309 void 1310 ami_scsi_cmd(struct scsi_xfer *xs) 1311 { 1312 struct scsi_link *link = xs->sc_link; 1313 struct ami_softc *sc = link->bus->sb_adapter_softc; 1314 struct device *dev = link->device_softc; 1315 struct ami_ccb *ccb; 1316 struct ami_iocmd *cmd; 1317 struct scsi_inquiry_data inq; 1318 struct scsi_sense_data sd; 1319 struct scsi_read_cap_data rcd; 1320 u_int8_t target = link->target; 1321 u_int32_t blockno, blockcnt; 1322 struct scsi_rw *rw; 1323 struct scsi_rw_big *rwb; 1324 bus_dma_segment_t *sgd; 1325 int error; 1326 int i; 1327 1328 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd ")); 1329 1330 if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present || 1331 link->lun != 0) { 1332 AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target)); 1333 /* XXX should be XS_SENSE and sense filled out */ 1334 xs->error = XS_DRIVER_STUFFUP; 1335 scsi_done(xs); 1336 return; 1337 } 1338 1339 xs->error = XS_NOERROR; 1340 1341 switch (xs->cmd->opcode) { 1342 case READ_COMMAND: 1343 case READ_BIG: 1344 case WRITE_COMMAND: 1345 case WRITE_BIG: 1346 /* deal with io outside the switch */ 1347 break; 1348 1349 case SYNCHRONIZE_CACHE: 1350 ccb = xs->io; 1351 1352 ccb->ccb_xs = xs; 1353 ccb->ccb_done = ami_done_flush; 1354 if (xs->timeout < 30000) 1355 xs->timeout = 30000; /* at least 30sec */ 1356 1357 cmd = &ccb->ccb_cmd; 1358 cmd->acc_cmd = AMI_FLUSH; 1359 1360 ami_start_xs(sc, ccb, xs); 1361 return; 1362 1363 case TEST_UNIT_READY: 1364 /* save off sd? after autoconf */ 1365 if (!cold) /* XXX bogus */ 1366 strlcpy(sc->sc_hdr[target].dev, dev->dv_xname, 1367 sizeof(sc->sc_hdr[target].dev)); 1368 case START_STOP: 1369 #if 0 1370 case VERIFY: 1371 #endif 1372 case PREVENT_ALLOW: 1373 AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode, 1374 target)); 1375 xs->error = XS_NOERROR; 1376 scsi_done(xs); 1377 return; 1378 1379 case REQUEST_SENSE: 1380 AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target)); 1381 bzero(&sd, sizeof(sd)); 1382 sd.error_code = SSD_ERRCODE_CURRENT; 1383 sd.segment = 0; 1384 sd.flags = SKEY_NO_SENSE; 1385 *(u_int32_t*)sd.info = htole32(0); 1386 sd.extra_len = 0; 1387 ami_copy_internal_data(xs, &sd, sizeof(sd)); 1388 1389 xs->error = XS_NOERROR; 1390 scsi_done(xs); 1391 return; 1392 1393 case INQUIRY: 1394 if (ISSET(((struct scsi_inquiry *)xs->cmd)->flags, SI_EVPD)) { 1395 xs->error = XS_DRIVER_STUFFUP; 1396 scsi_done(xs); 1397 return; 1398 } 1399 1400 AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target)); 1401 bzero(&inq, sizeof(inq)); 1402 inq.device = T_DIRECT; 1403 inq.dev_qual2 = 0; 1404 inq.version = 2; 1405 inq.response_format = 2; 1406 inq.additional_length = 32; 1407 inq.flags |= SID_CmdQue; 1408 strlcpy(inq.vendor, "AMI ", sizeof(inq.vendor)); 1409 snprintf(inq.product, sizeof(inq.product), 1410 "Host drive #%02d", target); 1411 strlcpy(inq.revision, " ", sizeof(inq.revision)); 1412 ami_copy_internal_data(xs, &inq, sizeof(inq)); 1413 1414 xs->error = XS_NOERROR; 1415 scsi_done(xs); 1416 return; 1417 1418 case READ_CAPACITY: 1419 AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target)); 1420 bzero(&rcd, sizeof(rcd)); 1421 _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr); 1422 _lto4b(AMI_SECTOR_SIZE, rcd.length); 1423 ami_copy_internal_data(xs, &rcd, sizeof(rcd)); 1424 1425 xs->error = XS_NOERROR; 1426 scsi_done(xs); 1427 return; 1428 1429 default: 1430 AMI_DPRINTF(AMI_D_CMD, ("unsupported scsi command %#x tgt %d ", 1431 xs->cmd->opcode, target)); 1432 1433 xs->error = XS_DRIVER_STUFFUP; 1434 scsi_done(xs); 1435 return; 1436 } 1437 1438 /* A read or write operation. */ 1439 if (xs->cmdlen == 6) { 1440 rw = (struct scsi_rw *)xs->cmd; 1441 blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); 1442 blockcnt = rw->length ? rw->length : 0x100; 1443 } else { 1444 rwb = (struct scsi_rw_big *)xs->cmd; 1445 blockno = _4btol(rwb->addr); 1446 blockcnt = _2btol(rwb->length); 1447 } 1448 1449 if (blockno >= sc->sc_hdr[target].hd_size || 1450 blockno + blockcnt > sc->sc_hdr[target].hd_size) { 1451 printf("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc), 1452 blockno, blockcnt, sc->sc_hdr[target].hd_size); 1453 xs->error = XS_DRIVER_STUFFUP; 1454 scsi_done(xs); 1455 return; 1456 } 1457 1458 ccb = xs->io; 1459 1460 ccb->ccb_xs = xs; 1461 ccb->ccb_done = ami_done_xs; 1462 1463 cmd = &ccb->ccb_cmd; 1464 cmd->acc_cmd = (xs->flags & SCSI_DATA_IN) ? AMI_READ : AMI_WRITE; 1465 cmd->acc_mbox.amb_nsect = htole16(blockcnt); 1466 cmd->acc_mbox.amb_lba = htole32(blockno); 1467 cmd->acc_mbox.amb_ldn = target; 1468 1469 error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap, 1470 xs->data, xs->datalen, NULL, 1471 (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1472 if (error) { 1473 if (error == EFBIG) 1474 printf("more than %d dma segs\n", AMI_MAXOFFSETS); 1475 else 1476 printf("error %d loading dma map\n", error); 1477 1478 xs->error = XS_DRIVER_STUFFUP; 1479 scsi_done(xs); 1480 return; 1481 } 1482 1483 sgd = ccb->ccb_dmamap->dm_segs; 1484 if (ccb->ccb_dmamap->dm_nsegs > 1) { 1485 struct ami_sgent *sgl = ccb->ccb_sglist; 1486 1487 cmd->acc_mbox.amb_nsge = ccb->ccb_dmamap->dm_nsegs; 1488 cmd->acc_mbox.amb_data = ccb->ccb_sglistpa; 1489 1490 for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) { 1491 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1492 sgl[i].asg_len = htole32(sgd[i].ds_len); 1493 } 1494 } else { 1495 cmd->acc_mbox.amb_nsge = 0; 1496 cmd->acc_mbox.amb_data = htole32(sgd->ds_addr); 1497 } 1498 1499 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1500 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1501 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1502 1503 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1504 ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? 1505 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1506 1507 ami_start_xs(sc, ccb, xs); 1508 } 1509 1510 int 1511 ami_intr(void *v) 1512 { 1513 struct ami_iocmd mbox; 1514 struct ami_softc *sc = v; 1515 struct ami_ccb *ccb; 1516 int i, rv = 0, ready; 1517 1518 mtx_enter(&sc->sc_cmd_mtx); 1519 while (!TAILQ_EMPTY(&sc->sc_ccb_runq) && sc->sc_done(sc, &mbox)) { 1520 AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); 1521 for (i = 0; i < mbox.acc_nstat; i++ ) { 1522 ready = mbox.acc_cmplidl[i] - 1; 1523 AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready)); 1524 1525 ccb = &sc->sc_ccbs[ready]; 1526 ccb->ccb_status = mbox.acc_status; 1527 ccb->ccb_state = AMI_CCB_READY; 1528 TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); 1529 1530 mtx_leave(&sc->sc_cmd_mtx); 1531 ccb->ccb_done(sc, ccb); 1532 mtx_enter(&sc->sc_cmd_mtx); 1533 1534 rv = 1; 1535 } 1536 } 1537 ready = (sc->sc_drainio && TAILQ_EMPTY(&sc->sc_ccb_runq)); 1538 mtx_leave(&sc->sc_cmd_mtx); 1539 1540 if (ready) 1541 wakeup(sc); 1542 else if (rv) 1543 ami_runqueue(sc); 1544 1545 AMI_DPRINTF(AMI_D_INTR, ("exit ")); 1546 return (rv); 1547 } 1548 1549 int 1550 ami_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag) 1551 { 1552 struct ami_softc *sc = link->bus->sb_adapter_softc; 1553 /* struct device *dev = (struct device *)link->device_softc; */ 1554 /* u_int8_t target = link->target; */ 1555 1556 if (sc->sc_ioctl) 1557 return (sc->sc_ioctl(&sc->sc_dev, cmd, addr)); 1558 else 1559 return (ENOTTY); 1560 } 1561 1562 #if NBIO > 0 1563 int 1564 ami_ioctl(struct device *dev, u_long cmd, caddr_t addr) 1565 { 1566 struct ami_softc *sc = (struct ami_softc *)dev; 1567 int error = 0; 1568 1569 AMI_DPRINTF(AMI_D_IOCTL, ("%s: ioctl ", DEVNAME(sc))); 1570 1571 if (sc->sc_flags & AMI_BROKEN) 1572 return (ENODEV); /* can't do this to broken device for now */ 1573 1574 switch (cmd) { 1575 case BIOCINQ: 1576 AMI_DPRINTF(AMI_D_IOCTL, ("inq ")); 1577 error = ami_ioctl_inq(sc, (struct bioc_inq *)addr); 1578 break; 1579 1580 case BIOCVOL: 1581 AMI_DPRINTF(AMI_D_IOCTL, ("vol ")); 1582 error = ami_ioctl_vol(sc, (struct bioc_vol *)addr); 1583 break; 1584 1585 case BIOCDISK: 1586 AMI_DPRINTF(AMI_D_IOCTL, ("disk ")); 1587 error = ami_ioctl_disk(sc, (struct bioc_disk *)addr); 1588 break; 1589 1590 case BIOCALARM: 1591 AMI_DPRINTF(AMI_D_IOCTL, ("alarm ")); 1592 error = ami_ioctl_alarm(sc, (struct bioc_alarm *)addr); 1593 break; 1594 1595 case BIOCSETSTATE: 1596 AMI_DPRINTF(AMI_D_IOCTL, ("setstate ")); 1597 error = ami_ioctl_setstate(sc, (struct bioc_setstate *)addr); 1598 break; 1599 1600 default: 1601 AMI_DPRINTF(AMI_D_IOCTL, (" invalid ioctl\n")); 1602 error = ENOTTY; 1603 } 1604 1605 return (error); 1606 } 1607 1608 int 1609 ami_drv_pt(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t *cmd, 1610 int clen, int blen, void *buf) 1611 { 1612 struct ami_ccb *ccb; 1613 struct ami_passthrough *pt; 1614 int error = 0; 1615 1616 rw_enter_write(&sc->sc_lock); 1617 1618 ccb = scsi_io_get(&sc->sc_iopool, 0); 1619 if (ccb == NULL) { 1620 error = ENOMEM; 1621 goto err; 1622 } 1623 1624 ccb->ccb_done = ami_done_ioctl; 1625 1626 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1627 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1628 1629 pt = ccb->ccb_pt; 1630 memset(pt, 0, sizeof *pt); 1631 pt->apt_channel = ch; 1632 pt->apt_target = tg; 1633 pt->apt_ncdb = clen; 1634 pt->apt_nsense = sizeof(struct scsi_sense_data); 1635 pt->apt_datalen = blen; 1636 pt->apt_data = 0; 1637 1638 bcopy(cmd, pt->apt_cdb, clen); 1639 1640 if (ami_load_ptmem(sc, ccb, buf, blen, 1, 0) != 0) { 1641 error = ENOMEM; 1642 goto ptmemerr; 1643 } 1644 1645 ami_start(sc, ccb); 1646 1647 while (ccb->ccb_state != AMI_CCB_READY) 1648 tsleep_nsec(ccb, PRIBIO, "ami_drv_pt", INFSLP); 1649 1650 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1651 ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); 1652 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1653 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1654 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1655 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1656 1657 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1658 error = EIO; 1659 else if (pt->apt_scsistat != 0x00) 1660 error = EIO; 1661 1662 ptmemerr: 1663 scsi_io_put(&sc->sc_iopool, ccb); 1664 1665 err: 1666 rw_exit_write(&sc->sc_lock); 1667 return (error); 1668 } 1669 1670 int 1671 ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page, 1672 void *inqbuf) 1673 { 1674 struct scsi_inquiry_data *inq = inqbuf; 1675 u_int8_t cdb[6]; 1676 int error = 0; 1677 1678 bzero(&cdb, sizeof cdb); 1679 1680 cdb[0] = INQUIRY; 1681 cdb[1] = 0; 1682 cdb[2] = 0; 1683 cdb[3] = 0; 1684 cdb[4] = sizeof(struct scsi_inquiry_data); 1685 cdb[5] = 0; 1686 if (page != 0) { 1687 cdb[1] = SI_EVPD; 1688 cdb[2] = page; 1689 } 1690 1691 error = ami_drv_pt(sc, ch, tg, cdb, 6, sizeof *inq, inqbuf); 1692 if (error) 1693 return (error); 1694 1695 if ((inq->device & SID_TYPE) != T_DIRECT) 1696 error = EINVAL; 1697 1698 return (error); 1699 } 1700 1701 int 1702 ami_drv_readcap(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, daddr_t *sz) 1703 { 1704 struct scsi_read_cap_data *rcd = NULL; 1705 struct scsi_read_cap_data_16 *rcd16 = NULL; 1706 u_int8_t cdb[16]; 1707 u_int32_t blksz; 1708 daddr_t noblk; 1709 int error = 0; 1710 1711 bzero(&cdb, sizeof cdb); 1712 cdb[0] = READ_CAPACITY; 1713 rcd = dma_alloc(sizeof(*rcd), PR_WAITOK); 1714 1715 error = ami_drv_pt(sc, ch, tg, cdb, 10, sizeof(*rcd), rcd); 1716 if (error) 1717 goto fail; 1718 1719 noblk = _4btol(rcd->addr); 1720 if (noblk == 0xffffffffllu) { 1721 /* huge disk */ 1722 bzero(&cdb, sizeof cdb); 1723 cdb[0] = READ_CAPACITY_16; 1724 rcd16 = dma_alloc(sizeof(*rcd16), PR_WAITOK); 1725 1726 error = ami_drv_pt(sc, ch, tg, cdb, 16, sizeof(*rcd16), rcd16); 1727 if (error) 1728 goto fail; 1729 1730 noblk = _8btol(rcd16->addr); 1731 blksz = _4btol(rcd16->length); 1732 } else 1733 blksz = _4btol(rcd->length); 1734 1735 if (blksz == 0) 1736 blksz = 512; 1737 *sz = noblk * blksz; 1738 1739 fail: 1740 if (rcd16) 1741 dma_free(rcd16, sizeof(*rcd16)); 1742 dma_free(rcd, sizeof(*rcd)); 1743 return (error); 1744 } 1745 1746 int 1747 ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, 1748 u_int8_t par3, size_t size, void *buffer) 1749 { 1750 struct ami_ccb *ccb; 1751 struct ami_iocmd *cmd; 1752 struct ami_mem *am = NULL; 1753 char *idata = NULL; 1754 int error = 0; 1755 1756 rw_enter_write(&sc->sc_lock); 1757 1758 if (opcode != AMI_CHSTATE) { 1759 ccb = scsi_io_get(&sc->sc_iopool, 0); 1760 if (ccb == NULL) { 1761 error = ENOMEM; 1762 goto err; 1763 } 1764 ccb->ccb_done = ami_done_ioctl; 1765 } else 1766 ccb = sc->sc_mgmtccb; 1767 1768 if (size) { 1769 if ((am = ami_allocmem(sc, size)) == NULL) { 1770 error = ENOMEM; 1771 goto memerr; 1772 } 1773 idata = AMIMEM_KVA(am); 1774 } 1775 1776 cmd = &ccb->ccb_cmd; 1777 cmd->acc_cmd = opcode; 1778 1779 /* 1780 * some commands require data to be written to idata before sending 1781 * command to fw 1782 */ 1783 switch (opcode) { 1784 case AMI_SPEAKER: 1785 *idata = par1; 1786 break; 1787 default: 1788 cmd->acc_io.aio_channel = par1; 1789 cmd->acc_io.aio_param = par2; 1790 cmd->acc_io.aio_pad[0] = par3; 1791 break; 1792 }; 1793 1794 cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0; 1795 1796 if (opcode != AMI_CHSTATE) { 1797 ami_start(sc, ccb); 1798 mtx_enter(&sc->sc_cmd_mtx); 1799 while (ccb->ccb_state != AMI_CCB_READY) 1800 msleep_nsec(ccb, &sc->sc_cmd_mtx, PRIBIO, "ami_mgmt", 1801 INFSLP); 1802 mtx_leave(&sc->sc_cmd_mtx); 1803 } else { 1804 /* change state must be run with id 0xfe and MUST be polled */ 1805 mtx_enter(&sc->sc_cmd_mtx); 1806 sc->sc_drainio = 1; 1807 while (!TAILQ_EMPTY(&sc->sc_ccb_runq)) { 1808 if (msleep_nsec(sc, &sc->sc_cmd_mtx, PRIBIO, 1809 "amimgmt", SEC_TO_NSEC(60)) == EWOULDBLOCK) { 1810 printf("%s: drain io timeout\n", DEVNAME(sc)); 1811 ccb->ccb_flags |= AMI_CCB_F_ERR; 1812 goto restartio; 1813 } 1814 } 1815 1816 error = sc->sc_poll(sc, &ccb->ccb_cmd); 1817 if (error == -1) 1818 ccb->ccb_flags |= AMI_CCB_F_ERR; 1819 1820 restartio: 1821 /* restart io */ 1822 sc->sc_drainio = 0; 1823 mtx_leave(&sc->sc_cmd_mtx); 1824 ami_runqueue(sc); 1825 } 1826 1827 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1828 error = EIO; 1829 else if (buffer && size) 1830 memcpy(buffer, idata, size); 1831 1832 if (am) 1833 ami_freemem(sc, am); 1834 memerr: 1835 if (opcode != AMI_CHSTATE) { 1836 scsi_io_put(&sc->sc_iopool, ccb); 1837 } else { 1838 ccb->ccb_flags = 0; 1839 ccb->ccb_state = AMI_CCB_FREE; 1840 } 1841 1842 err: 1843 rw_exit_write(&sc->sc_lock); 1844 return (error); 1845 } 1846 1847 int 1848 ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi) 1849 { 1850 struct ami_big_diskarray *p; /* struct too large for stack */ 1851 struct scsi_inquiry_data *inqbuf; 1852 struct ami_fc_einquiry einq; 1853 int ch, tg; 1854 int i, s, t, off; 1855 int error = 0, changes = 0; 1856 1857 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_EINQ3, 1858 AMI_FC_EINQ3_SOLICITED_FULL, 0, sizeof einq, &einq))) 1859 return (EINVAL); 1860 1861 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 1862 1863 if (einq.ain_drvinscnt == sc->sc_drvinscnt) { 1864 /* poke existing known drives to make sure they aren't gone */ 1865 for(i = 0; i < sc->sc_channels * 16; i++) { 1866 if (sc->sc_plist[i] == 0) 1867 continue; 1868 1869 ch = (i & 0xf0) >> 4; 1870 tg = i & 0x0f; 1871 if (ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 1872 /* drive is gone, force rescan */ 1873 changes = 1; 1874 break; 1875 } 1876 } 1877 if (changes == 0) { 1878 bcopy(&sc->sc_bi, bi, sizeof *bi); 1879 goto done; 1880 } 1881 } 1882 1883 sc->sc_drvinscnt = einq.ain_drvinscnt; 1884 1885 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 1886 if (!p) { 1887 error = ENOMEM; 1888 goto done; 1889 } 1890 1891 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, 1892 p))) { 1893 error = EINVAL; 1894 goto bail; 1895 } 1896 1897 bzero(sc->sc_plist, sizeof sc->sc_plist); 1898 1899 bi->bi_novol = p->ada_nld; 1900 bi->bi_nodisk = 0; 1901 strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); 1902 1903 /* count used disks, including failed ones */ 1904 for (i = 0; i < p->ada_nld; i++) 1905 for (s = 0; s < p->ald[i].adl_spandepth; s++) 1906 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 1907 off = p->ald[i].asp[s].adv[t].add_channel * 1908 AMI_MAX_TARGET + 1909 p->ald[i].asp[s].adv[t].add_target; 1910 1911 /* account for multi raid vol on same disk */ 1912 if (!sc->sc_plist[off]) { 1913 sc->sc_plist[off] = 1; 1914 bi->bi_nodisk++; 1915 } 1916 } 1917 1918 /* count unsued disks */ 1919 for(i = 0; i < sc->sc_channels * 16; i++) { 1920 if (sc->sc_plist[i]) 1921 continue; /* skip claimed drives */ 1922 1923 /* 1924 * hack to invalidate device type, needed for initiator id 1925 * on an unconnected channel. 1926 * XXX find out if we can determine this differently 1927 */ 1928 memset(inqbuf, 0xff, sizeof(*inqbuf)); 1929 1930 ch = (i & 0xf0) >> 4; 1931 tg = i & 0x0f; 1932 if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 1933 if ((inqbuf->device & SID_TYPE) != T_DIRECT) 1934 continue; 1935 bi->bi_novol++; 1936 bi->bi_nodisk++; 1937 sc->sc_plist[i] = 2; 1938 } else 1939 sc->sc_plist[i] = 0; 1940 } 1941 1942 bcopy(bi, &sc->sc_bi, sizeof sc->sc_bi); 1943 error = 0; 1944 bail: 1945 free(p, M_DEVBUF, sizeof *p); 1946 done: 1947 dma_free(inqbuf, sizeof(*inqbuf)); 1948 return (error); 1949 } 1950 1951 int 1952 ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p) 1953 { 1954 int i, ld = p->ada_nld, error = EINVAL; 1955 1956 for(i = 0; i < sc->sc_channels * 16; i++) { 1957 /* skip claimed/unused drives */ 1958 if (sc->sc_plist[i] != 2) 1959 continue; 1960 1961 /* are we it? */ 1962 if (ld != bv->bv_volid) { 1963 ld++; 1964 continue; 1965 } 1966 1967 bv->bv_status = BIOC_SVONLINE; 1968 bv->bv_size = (uint64_t)p->apd[i].adp_size * 1969 (uint64_t)512; 1970 bv->bv_nodisk = 1; 1971 strlcpy(bv->bv_dev, 1972 sc->sc_hdr[bv->bv_volid].dev, 1973 sizeof(bv->bv_dev)); 1974 1975 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE 1976 && p->apd[i].adp_type == 0) 1977 bv->bv_level = -1; 1978 else 1979 bv->bv_level = -2; 1980 1981 error = 0; 1982 goto bail; 1983 } 1984 1985 bail: 1986 return (error); 1987 } 1988 1989 int 1990 ami_disk(struct ami_softc *sc, struct bioc_disk *bd, 1991 struct ami_big_diskarray *p) 1992 { 1993 char vend[8+16+4+1], *vendp; 1994 char ser[32 + 1]; 1995 struct scsi_inquiry_data *inqbuf; 1996 struct scsi_vpd_serial *vpdbuf; 1997 int i, ld = p->ada_nld, error = EINVAL; 1998 u_int8_t ch, tg; 1999 daddr_t sz = 0; 2000 2001 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2002 vpdbuf = dma_alloc(sizeof(*vpdbuf), PR_WAITOK); 2003 2004 for(i = 0; i < sc->sc_channels * 16; i++) { 2005 /* skip claimed/unused drives */ 2006 if (sc->sc_plist[i] != 2) 2007 continue; 2008 2009 /* are we it? */ 2010 if (ld != bd->bd_volid) { 2011 ld++; 2012 continue; 2013 } 2014 2015 ch = (i & 0xf0) >> 4; 2016 tg = i & 0x0f; 2017 if (ami_drv_inq(sc, ch, tg, 0, inqbuf)) 2018 goto bail; 2019 2020 vendp = inqbuf->vendor; 2021 bcopy(vendp, vend, sizeof vend - 1); 2022 2023 vend[sizeof vend - 1] = '\0'; 2024 strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor)); 2025 2026 if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) { 2027 bcopy(vpdbuf->serial, ser, sizeof ser - 1); 2028 ser[sizeof ser - 1] = '\0'; 2029 if (_2btol(vpdbuf->hdr.page_length) < sizeof ser) 2030 ser[_2btol(vpdbuf->hdr.page_length)] = '\0'; 2031 strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial)); 2032 } 2033 2034 error = ami_drv_readcap(sc, ch, tg, &sz); 2035 if (error) 2036 goto bail; 2037 2038 bd->bd_size = sz; 2039 bd->bd_channel = ch; 2040 bd->bd_target = tg; 2041 2042 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2043 sizeof(bd->bd_procdev)); 2044 2045 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE) 2046 bd->bd_status = BIOC_SDHOTSPARE; 2047 else 2048 bd->bd_status = BIOC_SDUNUSED; 2049 2050 #ifdef AMI_DEBUG 2051 if (p->apd[i].adp_type != 0) 2052 printf("invalid disk type: %d %d %x inquiry type: %x\n", 2053 ch, tg, p->apd[i].adp_type, inqbuf->device); 2054 #endif /* AMI_DEBUG */ 2055 2056 error = 0; 2057 goto bail; 2058 } 2059 2060 bail: 2061 dma_free(inqbuf, sizeof(*inqbuf)); 2062 dma_free(vpdbuf, sizeof(*vpdbuf)); 2063 return (error); 2064 } 2065 2066 int 2067 ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv) 2068 { 2069 struct ami_big_diskarray *p; /* struct too large for stack */ 2070 int i, s, t, off; 2071 int error = 0; 2072 struct ami_progress perc; 2073 u_int8_t bgi[5]; /* 40 LD, 1 bit per LD if BGI is active */ 2074 2075 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 2076 if (!p) 2077 return (ENOMEM); 2078 2079 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2080 goto bail; 2081 2082 if (bv->bv_volid >= p->ada_nld) { 2083 error = ami_vol(sc, bv, p); 2084 goto bail; 2085 } 2086 2087 i = bv->bv_volid; 2088 2089 switch (p->ald[i].adl_status) { 2090 case AMI_RDRV_OFFLINE: 2091 bv->bv_status = BIOC_SVOFFLINE; 2092 break; 2093 2094 case AMI_RDRV_DEGRADED: 2095 bv->bv_status = BIOC_SVDEGRADED; 2096 break; 2097 2098 case AMI_RDRV_OPTIMAL: 2099 bv->bv_status = BIOC_SVONLINE; 2100 bv->bv_percent = -1; 2101 2102 /* get BGI progress here and over-ride status if so */ 2103 memset(bgi, 0, sizeof bgi); 2104 if (ami_mgmt(sc, AMI_MISC, AMI_GET_BGI, 0, 0, sizeof bgi, &bgi)) 2105 break; 2106 2107 if ((bgi[i / 8] & (1 << i % 8)) == 0) 2108 break; 2109 2110 if (!ami_mgmt(sc, AMI_GCHECKPROGR, i, 0, 0, sizeof perc, &perc)) 2111 if (perc.apr_progress < 100) { 2112 bv->bv_status = BIOC_SVSCRUB; 2113 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2114 perc.apr_progress; 2115 } 2116 break; 2117 2118 default: 2119 bv->bv_status = BIOC_SVINVALID; 2120 } 2121 2122 /* over-ride status if a pd is in rebuild status for this ld */ 2123 for (s = 0; s < p->ald[i].adl_spandepth; s++) 2124 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2125 off = p->ald[i].asp[s].adv[t].add_channel * 2126 AMI_MAX_TARGET + 2127 p->ald[i].asp[s].adv[t].add_target; 2128 2129 if (p->apd[off].adp_ostatus != AMI_PD_RBLD) 2130 continue; 2131 2132 /* get rebuild progress from pd 0 */ 2133 bv->bv_status = BIOC_SVREBUILD; 2134 if (ami_mgmt(sc, AMI_GRBLDPROGR, 2135 p->ald[i].asp[s].adv[t].add_channel, 2136 p->ald[i].asp[s].adv[t].add_target, 0, 2137 sizeof perc, &perc)) 2138 bv->bv_percent = -1; 2139 else 2140 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2141 perc.apr_progress; 2142 break; 2143 } 2144 2145 bv->bv_size = 0; 2146 bv->bv_level = p->ald[i].adl_raidlvl; 2147 bv->bv_nodisk = 0; 2148 2149 for (s = 0; s < p->ald[i].adl_spandepth; s++) { 2150 for (t = 0; t < p->ald[i].adl_nstripes; t++) 2151 bv->bv_nodisk++; 2152 2153 switch (bv->bv_level) { 2154 case 0: 2155 bv->bv_size += p->ald[i].asp[s].ads_length * 2156 p->ald[i].adl_nstripes; 2157 break; 2158 2159 case 1: 2160 bv->bv_size += p->ald[i].asp[s].ads_length; 2161 break; 2162 2163 case 5: 2164 bv->bv_size += p->ald[i].asp[s].ads_length * 2165 (p->ald[i].adl_nstripes - 1); 2166 break; 2167 } 2168 } 2169 2170 if (p->ald[i].adl_spandepth > 1) 2171 bv->bv_level *= 10; 2172 2173 bv->bv_size *= (uint64_t)512; 2174 2175 strlcpy(bv->bv_dev, sc->sc_hdr[i].dev, sizeof(bv->bv_dev)); 2176 2177 bail: 2178 free(p, M_DEVBUF, sizeof *p); 2179 2180 return (error); 2181 } 2182 2183 int 2184 ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd) 2185 { 2186 struct scsi_inquiry_data *inqbuf; 2187 struct scsi_vpd_serial *vpdbuf; 2188 struct ami_big_diskarray *p; /* struct too large for stack */ 2189 int i, s, t, d; 2190 int off; 2191 int error = EINVAL; 2192 u_int16_t ch, tg; 2193 char vend[8+16+4+1], *vendp; 2194 char ser[32 + 1]; 2195 2196 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2197 vpdbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2198 p = malloc(sizeof *p, M_DEVBUF, M_WAITOK); 2199 2200 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2201 goto bail; 2202 2203 if (bd->bd_volid >= p->ada_nld) { 2204 error = ami_disk(sc, bd, p); 2205 goto bail; 2206 } 2207 2208 i = bd->bd_volid; 2209 for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++) 2210 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2211 if (d != bd->bd_diskid) { 2212 d++; 2213 continue; 2214 } 2215 2216 off = p->ald[i].asp[s].adv[t].add_channel * 2217 AMI_MAX_TARGET + 2218 p->ald[i].asp[s].adv[t].add_target; 2219 2220 bd->bd_size = (uint64_t)p->apd[off].adp_size * 2221 (uint64_t)512; 2222 2223 switch (p->apd[off].adp_ostatus) { 2224 case AMI_PD_UNCNF: 2225 bd->bd_status = BIOC_SDUNUSED; 2226 break; 2227 2228 case AMI_PD_ONLINE: 2229 bd->bd_status = BIOC_SDONLINE; 2230 break; 2231 2232 case AMI_PD_FAILED: 2233 bd->bd_status = BIOC_SDFAILED; 2234 bd->bd_size = 0; 2235 break; 2236 2237 case AMI_PD_RBLD: 2238 bd->bd_status = BIOC_SDREBUILD; 2239 break; 2240 2241 case AMI_PD_HOTSPARE: 2242 bd->bd_status = BIOC_SDHOTSPARE; 2243 break; 2244 2245 default: 2246 bd->bd_status = BIOC_SDINVALID; 2247 bd->bd_size = 0; 2248 } 2249 2250 2251 ch = p->ald[i].asp[s].adv[t].add_target >> 4; 2252 tg = p->ald[i].asp[s].adv[t].add_target & 0x0f; 2253 2254 bd->bd_channel = ch; 2255 bd->bd_target = tg; 2256 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2257 sizeof(bd->bd_procdev)); 2258 2259 /* if we are failed don't query drive */ 2260 if (bd->bd_size == 0) { 2261 bzero(&bd->bd_vendor, sizeof(bd->bd_vendor)); 2262 bzero(&bd->bd_serial, sizeof(bd->bd_serial)); 2263 goto done; 2264 } 2265 2266 if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 2267 vendp = inqbuf->vendor; 2268 bcopy(vendp, vend, sizeof vend - 1); 2269 vend[sizeof vend - 1] = '\0'; 2270 strlcpy(bd->bd_vendor, vend, 2271 sizeof(bd->bd_vendor)); 2272 } 2273 2274 if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) { 2275 bcopy(vpdbuf->serial, ser, sizeof ser - 1); 2276 ser[sizeof ser - 1] = '\0'; 2277 if (_2btol(vpdbuf->hdr.page_length) < 2278 sizeof(ser)) 2279 ser[_2btol(vpdbuf->hdr.page_length)] = 2280 '\0'; 2281 strlcpy(bd->bd_serial, ser, 2282 sizeof(bd->bd_serial)); 2283 } 2284 goto done; 2285 } 2286 2287 done: 2288 error = 0; 2289 bail: 2290 free(p, M_DEVBUF, sizeof *p); 2291 dma_free(vpdbuf, sizeof(*vpdbuf)); 2292 dma_free(inqbuf, sizeof(*inqbuf)); 2293 2294 return (error); 2295 } 2296 2297 int ami_ioctl_alarm(struct ami_softc *sc, struct bioc_alarm *ba) 2298 { 2299 int error = 0; 2300 u_int8_t func, ret; 2301 2302 switch(ba->ba_opcode) { 2303 case BIOC_SADISABLE: 2304 func = AMI_SPKR_OFF; 2305 break; 2306 2307 case BIOC_SAENABLE: 2308 func = AMI_SPKR_ON; 2309 break; 2310 2311 case BIOC_SASILENCE: 2312 func = AMI_SPKR_SHUT; 2313 break; 2314 2315 case BIOC_GASTATUS: 2316 func = AMI_SPKR_GVAL; 2317 break; 2318 2319 case BIOC_SATEST: 2320 func = AMI_SPKR_TEST; 2321 break; 2322 2323 default: 2324 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocalarm invalid opcode %x\n", 2325 DEVNAME(sc), ba->ba_opcode)); 2326 return (EINVAL); 2327 } 2328 2329 if (!(error = ami_mgmt(sc, AMI_SPEAKER, func, 0, 0, sizeof ret, 2330 &ret))) { 2331 if (ba->ba_opcode == BIOC_GASTATUS) 2332 ba->ba_status = ret; 2333 else 2334 ba->ba_status = 0; 2335 } 2336 2337 return (error); 2338 } 2339 2340 int 2341 ami_ioctl_setstate(struct ami_softc *sc, struct bioc_setstate *bs) 2342 { 2343 struct scsi_inquiry_data *inqbuf; 2344 int func, error = 0; 2345 2346 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2347 2348 switch (bs->bs_status) { 2349 case BIOC_SSONLINE: 2350 func = AMI_STATE_ON; 2351 break; 2352 2353 case BIOC_SSOFFLINE: 2354 func = AMI_STATE_FAIL; 2355 break; 2356 2357 case BIOC_SSHOTSPARE: 2358 if (ami_drv_inq(sc, bs->bs_channel, bs->bs_target, 0, 2359 inqbuf)) { 2360 error = EINVAL; 2361 goto done; 2362 } 2363 2364 func = AMI_STATE_SPARE; 2365 break; 2366 2367 default: 2368 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocsetstate invalid opcode %x\n" 2369 , DEVNAME(sc), bs->bs_status)); 2370 error = EINVAL; 2371 goto done; 2372 } 2373 2374 if ((error = ami_mgmt(sc, AMI_CHSTATE, bs->bs_channel, bs->bs_target, 2375 func, 0, NULL))) 2376 goto done; 2377 2378 done: 2379 dma_free(inqbuf, sizeof(*inqbuf)); 2380 return (error); 2381 } 2382 2383 #ifndef SMALL_KERNEL 2384 int 2385 ami_create_sensors(struct ami_softc *sc) 2386 { 2387 struct device *dev; 2388 struct scsibus_softc *ssc = NULL; 2389 struct scsi_link *link; 2390 int i; 2391 2392 TAILQ_FOREACH(dev, &alldevs, dv_list) { 2393 if (dev->dv_parent != &sc->sc_dev) 2394 continue; 2395 2396 /* check if this is the scsibus for the logical disks */ 2397 ssc = (struct scsibus_softc *)dev; 2398 if (ssc == sc->sc_scsibus) 2399 break; 2400 } 2401 2402 if (ssc == NULL) 2403 return (1); 2404 2405 sc->sc_sensors = mallocarray(sc->sc_nunits, sizeof(struct ksensor), 2406 M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 2407 if (sc->sc_sensors == NULL) 2408 return (1); 2409 2410 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 2411 sizeof(sc->sc_sensordev.xname)); 2412 2413 for (i = 0; i < sc->sc_nunits; i++) { 2414 link = scsi_get_link(ssc, i, 0); 2415 if (link == NULL) 2416 goto bad; 2417 2418 dev = link->device_softc; 2419 2420 sc->sc_sensors[i].type = SENSOR_DRIVE; 2421 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2422 2423 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, 2424 sizeof(sc->sc_sensors[i].desc)); 2425 2426 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 2427 } 2428 2429 sc->sc_bd = malloc(sizeof(*sc->sc_bd), M_DEVBUF, M_WAITOK|M_CANFAIL); 2430 if (sc->sc_bd == NULL) 2431 goto bad; 2432 2433 if (sensor_task_register(sc, ami_refresh_sensors, 10) == NULL) 2434 goto freebd; 2435 2436 sensordev_install(&sc->sc_sensordev); 2437 2438 return (0); 2439 2440 freebd: 2441 free(sc->sc_bd, M_DEVBUF, sizeof(*sc->sc_bd)); 2442 bad: 2443 free(sc->sc_sensors, M_DEVBUF, sc->sc_nunits * sizeof(struct ksensor)); 2444 2445 return (1); 2446 } 2447 2448 void 2449 ami_refresh_sensors(void *arg) 2450 { 2451 struct ami_softc *sc = arg; 2452 int i; 2453 2454 if (ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof(*sc->sc_bd), 2455 sc->sc_bd)) { 2456 for (i = 0; i < sc->sc_nunits; i++) { 2457 sc->sc_sensors[i].value = 0; /* unknown */ 2458 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2459 } 2460 return; 2461 } 2462 2463 for (i = 0; i < sc->sc_nunits; i++) { 2464 switch (sc->sc_bd->ald[i].adl_status) { 2465 case AMI_RDRV_OFFLINE: 2466 sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; 2467 sc->sc_sensors[i].status = SENSOR_S_CRIT; 2468 break; 2469 2470 case AMI_RDRV_DEGRADED: 2471 sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; 2472 sc->sc_sensors[i].status = SENSOR_S_WARN; 2473 break; 2474 2475 case AMI_RDRV_OPTIMAL: 2476 sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; 2477 sc->sc_sensors[i].status = SENSOR_S_OK; 2478 break; 2479 2480 default: 2481 sc->sc_sensors[i].value = 0; /* unknown */ 2482 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2483 } 2484 } 2485 } 2486 #endif /* SMALL_KERNEL */ 2487 #endif /* NBIO > 0 */ 2488 2489 #ifdef AMI_DEBUG 2490 void 2491 ami_print_mbox(struct ami_iocmd *mbox) 2492 { 2493 int i; 2494 2495 printf("acc_cmd: %d aac_id: %d acc_busy: %d acc_nstat: %d ", 2496 mbox->acc_cmd, mbox->acc_id, mbox->acc_busy, mbox->acc_nstat); 2497 printf("acc_status: %d acc_poll: %d acc_ack: %d\n", 2498 mbox->acc_status, mbox->acc_poll, mbox->acc_ack); 2499 2500 printf("acc_cmplidl: "); 2501 for (i = 0; i < AMI_MAXSTATACK; i++) { 2502 printf("[%d] = %d ", i, mbox->acc_cmplidl[i]); 2503 } 2504 2505 printf("\n"); 2506 } 2507 #endif /* AMI_DEBUG */ 2508