1 /* $OpenBSD: ami.c,v 1.241 2020/02/15 18:02:00 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%x 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%x 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_link.openings = 1; 481 sc->sc_maxcmds = 1; 482 sc->sc_maxunits = 1; 483 } else { 484 sc->sc_maxunits = AMI_BIG_MAX_LDRIVES; 485 if (sc->sc_maxcmds > AMI_MAXCMDS) 486 sc->sc_maxcmds = AMI_MAXCMDS; 487 /* 488 * Reserve ccb's for ioctl's and raw commands to 489 * processors/enclosures by lowering the number of 490 * openings available for logical units. 491 */ 492 sc->sc_maxcmds -= AMI_MAXIOCTLCMDS + AMI_MAXPROCS * 493 AMI_MAXRAWCMDS * sc->sc_channels; 494 495 sc->sc_link.openings = sc->sc_maxcmds; 496 } 497 498 if (ami_alloc_ccbs(sc, AMI_MAXCMDS + 1) != 0) { 499 /* error already printed */ 500 goto free_mbox; 501 } 502 503 ami_freemem(sc, am); 504 505 /* hack for hp netraid version encoding */ 506 if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' && 507 sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' && 508 'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' && 509 sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') { 510 511 snprintf(sc->sc_fwver, sizeof sc->sc_fwver, "%c.%02d.%02d", 512 sc->sc_fwver[2], sc->sc_fwver[1], sc->sc_fwver[0]); 513 snprintf(sc->sc_biosver, sizeof sc->sc_biosver, "%c.%02d.%02d", 514 sc->sc_biosver[2], sc->sc_biosver[1], sc->sc_biosver[0]); 515 } 516 517 /* TODO: fetch & print cache strategy */ 518 /* TODO: fetch & print scsi and raid info */ 519 520 sc->sc_link.adapter_softc = sc; 521 sc->sc_link.adapter = &ami_switch; 522 sc->sc_link.adapter_target = sc->sc_maxunits; 523 sc->sc_link.adapter_buswidth = sc->sc_maxunits; 524 sc->sc_link.pool = &sc->sc_iopool; 525 526 #ifdef AMI_DEBUG 527 printf(", FW %s, BIOS v%s, %dMB RAM\n" 528 "%s: %d channels, %d %ss, %d logical drives, " 529 "openings %d, max commands %d, quirks: %04x\n", 530 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 531 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits, 532 sc->sc_link.openings, sc->sc_maxcmds, sc->sc_flags); 533 #else 534 printf(", FW %s, BIOS v%s, %dMB RAM\n" 535 "%s: %d channels, %d %ss, %d logical drives\n", 536 sc->sc_fwver, sc->sc_biosver, sc->sc_memory, DEVNAME(sc), 537 sc->sc_channels, sc->sc_targets, p, sc->sc_nunits); 538 #endif /* AMI_DEBUG */ 539 540 if (sc->sc_flags & AMI_BROKEN && sc->sc_nunits > 1) 541 printf("%s: firmware buggy, limiting access to first logical " 542 "disk\n", DEVNAME(sc)); 543 544 /* lock around ioctl requests */ 545 rw_init(&sc->sc_lock, NULL); 546 547 bzero(&saa, sizeof(saa)); 548 saa.saa_sc_link = &sc->sc_link; 549 550 config_found(&sc->sc_dev, &saa, scsiprint); 551 552 /* can't do bioctls, sensors, or pass-through on broken devices */ 553 if (sc->sc_flags & AMI_BROKEN) 554 return (0); 555 556 #if NBIO > 0 557 if (bio_register(&sc->sc_dev, ami_ioctl) != 0) 558 printf("%s: controller registration failed\n", DEVNAME(sc)); 559 else 560 sc->sc_ioctl = ami_ioctl; 561 562 #ifndef SMALL_KERNEL 563 if (ami_create_sensors(sc) != 0) 564 printf("%s: unable to create sensors\n", DEVNAME(sc)); 565 #endif 566 #endif 567 568 rsc = mallocarray(sc->sc_channels, sizeof(struct ami_rawsoftc), 569 M_DEVBUF, M_NOWAIT|M_ZERO); 570 if (!rsc) { 571 printf("%s: no memory for raw interface\n", DEVNAME(sc)); 572 return (0); 573 } 574 575 for (sc->sc_rawsoftcs = rsc; 576 rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) { 577 578 struct scsibus_softc *ptbus; 579 struct scsi_link *proclink; 580 struct device *procdev; 581 582 rsc->sc_softc = sc; 583 rsc->sc_channel = rsc - sc->sc_rawsoftcs; 584 rsc->sc_link.openings = sc->sc_maxcmds; 585 rsc->sc_link.adapter_softc = rsc; 586 rsc->sc_link.adapter = &ami_raw_switch; 587 rsc->sc_proctarget = -1; 588 /* TODO fetch it from the controller */ 589 rsc->sc_link.adapter_target = 16; 590 rsc->sc_link.adapter_buswidth = 16; 591 rsc->sc_link.pool = &sc->sc_iopool; 592 593 bzero(&saa, sizeof(saa)); 594 saa.saa_sc_link = &rsc->sc_link; 595 596 ptbus = (struct scsibus_softc *)config_found(&sc->sc_dev, 597 &saa, scsiprint); 598 599 if (ptbus == NULL || rsc->sc_proctarget == -1) 600 continue; 601 602 proclink = scsi_get_link(ptbus, rsc->sc_proctarget, 0); 603 if (proclink == NULL) 604 continue; 605 606 procdev = proclink->device_softc; 607 strlcpy(rsc->sc_procdev, procdev->dv_xname, 608 sizeof(rsc->sc_procdev)); 609 } 610 611 return (0); 612 613 free_mbox: 614 ami_freemem(sc, sc->sc_mbox_am); 615 free_idata: 616 ami_freemem(sc, am); 617 618 return (1); 619 } 620 621 int 622 ami_quartz_init(struct ami_softc *sc) 623 { 624 ami_write(sc, AMI_QIDB, 0); 625 626 return (0); 627 } 628 629 int 630 ami_quartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 631 { 632 if (sc->sc_mbox->acc_busy) { 633 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 634 return (EBUSY); 635 } 636 637 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 638 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 639 sizeof(struct ami_iocmd), BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 640 641 sc->sc_mbox->acc_busy = 1; 642 sc->sc_mbox->acc_poll = 0; 643 sc->sc_mbox->acc_ack = 0; 644 645 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 646 647 return (0); 648 } 649 650 int 651 ami_quartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 652 { 653 u_int32_t i, n; 654 u_int8_t nstat, status; 655 u_int8_t completed[AMI_MAXSTATACK]; 656 657 if (ami_read(sc, AMI_QODB) != AMI_QODB_READY) 658 return (0); /* nothing to do */ 659 660 ami_write(sc, AMI_QODB, AMI_QODB_READY); 661 662 /* 663 * The following sequence is not supposed to have a timeout clause 664 * since the firmware has a "guarantee" that all commands will 665 * complete. The choice is either panic or hoping for a miracle 666 * and that the IOs will complete much later. 667 */ 668 i = 0; 669 while ((nstat = sc->sc_mbox->acc_nstat) == 0xff) { 670 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 671 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTREAD); 672 delay(1); 673 if (i++ > 1000000) 674 return (0); /* nothing to do */ 675 } 676 sc->sc_mbox->acc_nstat = 0xff; 677 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 678 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 679 680 /* wait until fw wrote out all completions */ 681 i = 0; 682 AMI_DPRINTF(AMI_D_CMD, ("aqd %d ", nstat)); 683 for (n = 0; n < nstat; n++) { 684 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 685 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 686 while ((completed[n] = sc->sc_mbox->acc_cmplidl[n]) == 0xff) { 687 delay(1); 688 if (i++ > 1000000) 689 return (0); /* nothing to do */ 690 } 691 sc->sc_mbox->acc_cmplidl[n] = 0xff; 692 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 693 sizeof(struct ami_iocmd), BUS_DMASYNC_POSTWRITE); 694 } 695 696 /* this should never happen, someone screwed up the completion status */ 697 if ((status = sc->sc_mbox->acc_status) == 0xff) 698 panic("%s: status 0xff from the firmware", DEVNAME(sc)); 699 700 sc->sc_mbox->acc_status = 0xff; 701 702 /* copy mailbox to temporary one and fixup other changed values */ 703 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 704 BUS_DMASYNC_POSTWRITE); 705 memcpy(mbox, (struct ami_iocmd *)sc->sc_mbox, 16); 706 mbox->acc_nstat = nstat; 707 mbox->acc_status = status; 708 for (n = 0; n < nstat; n++) 709 mbox->acc_cmplidl[n] = completed[n]; 710 711 /* ack interrupt */ 712 ami_write(sc, AMI_QIDB, AMI_QIDB_ACK); 713 714 return (1); /* ready to complete all IOs in acc_cmplidl */ 715 } 716 717 int 718 ami_quartz_poll(struct ami_softc *sc, struct ami_iocmd *cmd) 719 { 720 /* struct scsi_xfer *xs = ccb->ccb_xs; */ 721 u_int32_t i; 722 u_int8_t status; 723 724 splassert(IPL_BIO); 725 726 if (sc->sc_dis_poll) 727 return (-1); /* fail */ 728 729 i = 0; 730 while (sc->sc_mbox->acc_busy && (i < AMI_MAX_BUSYWAIT)) { 731 delay(1); 732 i++; 733 } 734 if (sc->sc_mbox->acc_busy) { 735 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 736 return (-1); 737 } 738 739 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 740 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 741 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 742 743 sc->sc_mbox->acc_id = 0xfe; 744 sc->sc_mbox->acc_busy = 1; 745 sc->sc_mbox->acc_poll = 0; 746 sc->sc_mbox->acc_ack = 0; 747 sc->sc_mbox->acc_nstat = 0xff; 748 sc->sc_mbox->acc_status = 0xff; 749 750 /* send command to firmware */ 751 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_EXEC)); 752 753 i = 0; 754 while ((sc->sc_mbox->acc_nstat == 0xff) && (i < AMI_MAX_POLLWAIT)) { 755 delay(1); 756 i++; 757 } 758 if (i >= AMI_MAX_POLLWAIT) { 759 printf("%s: command not accepted, polling disabled\n", 760 DEVNAME(sc)); 761 sc->sc_dis_poll = 1; 762 return (-1); 763 } 764 765 /* poll firmware */ 766 i = 0; 767 while ((sc->sc_mbox->acc_poll != 0x77) && (i < AMI_MAX_POLLWAIT)) { 768 delay(1); 769 i++; 770 } 771 if (i >= AMI_MAX_POLLWAIT) { 772 printf("%s: firmware didn't reply, polling disabled\n", 773 DEVNAME(sc)); 774 sc->sc_dis_poll = 1; 775 return (-1); 776 } 777 778 /* ack */ 779 ami_write(sc, AMI_QIDB, sc->sc_mbox_pa | htole32(AMI_QIDB_ACK)); 780 781 i = 0; 782 while((ami_read(sc, AMI_QIDB) & AMI_QIDB_ACK) && 783 (i < AMI_MAX_POLLWAIT)) { 784 delay(1); 785 i++; 786 } 787 if (i >= AMI_MAX_POLLWAIT) { 788 printf("%s: firmware didn't ack the ack, polling disabled\n", 789 DEVNAME(sc)); 790 sc->sc_dis_poll = 1; 791 return (-1); 792 } 793 794 sc->sc_mbox->acc_poll = 0; 795 sc->sc_mbox->acc_ack = 0x77; 796 status = sc->sc_mbox->acc_status; 797 sc->sc_mbox->acc_nstat = 0xff; 798 sc->sc_mbox->acc_status = 0xff; 799 800 for (i = 0; i < AMI_MAXSTATACK; i++) 801 sc->sc_mbox->acc_cmplidl[i] = 0xff; 802 803 return (status); 804 } 805 806 int 807 ami_schwartz_init(struct ami_softc *sc) 808 { 809 u_int32_t a = (u_int32_t)sc->sc_mbox_pa; 810 811 bus_space_write_4(sc->sc_iot, sc->sc_ioh, AMI_SMBADDR, a); 812 /* XXX 40bit address ??? */ 813 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SMBENA, 0); 814 815 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 816 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM, AMI_SEIM_ENA | 817 bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SIEM)); 818 819 return (0); 820 } 821 822 int 823 ami_schwartz_exec(struct ami_softc *sc, struct ami_iocmd *cmd) 824 { 825 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 826 AMI_SMBST_BUSY) { 827 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 828 return (EBUSY); 829 } 830 831 memcpy((struct ami_iocmd *)sc->sc_mbox, cmd, 16); 832 sc->sc_mbox->acc_busy = 1; 833 sc->sc_mbox->acc_poll = 0; 834 sc->sc_mbox->acc_ack = 0; 835 836 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 837 return (0); 838 } 839 840 int 841 ami_schwartz_done(struct ami_softc *sc, struct ami_iocmd *mbox) 842 { 843 u_int8_t stat; 844 845 #if 0 846 /* do not scramble the busy mailbox */ 847 if (sc->sc_mbox->acc_busy) 848 return (0); 849 #endif 850 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 851 AMI_SMBST_BUSY) 852 return (0); 853 854 stat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 855 if (stat & AMI_ISTAT_PEND) { 856 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, stat); 857 858 *mbox = *sc->sc_mbox; 859 AMI_DPRINTF(AMI_D_CMD, ("asd %d ", mbox->acc_nstat)); 860 861 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, 862 AMI_SCMD_ACK); 863 864 return (1); 865 } 866 867 return (0); 868 } 869 870 int 871 ami_schwartz_poll(struct ami_softc *sc, struct ami_iocmd *mbox) 872 { 873 u_int8_t status; 874 u_int32_t i; 875 int rv; 876 877 splassert(IPL_BIO); 878 879 if (sc->sc_dis_poll) 880 return (-1); /* fail */ 881 882 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 883 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 884 AMI_SMBST_BUSY)) 885 break; 886 delay(1); 887 } 888 if (i >= AMI_MAX_POLLWAIT) { 889 AMI_DPRINTF(AMI_D_CMD, ("mbox_busy ")); 890 return (-1); 891 } 892 893 memcpy((struct ami_iocmd *)sc->sc_mbox, mbox, 16); 894 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 16, 895 BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); 896 897 sc->sc_mbox->acc_busy = 1; 898 sc->sc_mbox->acc_poll = 0; 899 sc->sc_mbox->acc_ack = 0; 900 /* send command to firmware */ 901 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_EXEC); 902 903 /* wait until no longer busy */ 904 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 905 if (!(bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_SMBSTAT) & 906 AMI_SMBST_BUSY)) 907 break; 908 delay(1); 909 } 910 if (i >= AMI_MAX_POLLWAIT) { 911 printf("%s: command not accepted, polling disabled\n", 912 DEVNAME(sc)); 913 sc->sc_dis_poll = 1; 914 return (-1); 915 } 916 917 /* wait for interrupt bit */ 918 for (i = 0; i < AMI_MAX_POLLWAIT; i++) { 919 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT); 920 if (status & AMI_ISTAT_PEND) 921 break; 922 delay(1); 923 } 924 if (i >= AMI_MAX_POLLWAIT) { 925 printf("%s: interrupt didn't arrive, polling disabled\n", 926 DEVNAME(sc)); 927 sc->sc_dis_poll = 1; 928 return (-1); 929 } 930 931 /* write ststus back to firmware */ 932 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_ISTAT, status); 933 934 /* copy mailbox and status back */ 935 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_mbox_am), 0, 936 sizeof(struct ami_iocmd), BUS_DMASYNC_PREREAD); 937 *mbox = *sc->sc_mbox; 938 rv = sc->sc_mbox->acc_status; 939 940 /* ack interrupt */ 941 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMI_SCMD, AMI_SCMD_ACK); 942 943 return (rv); 944 } 945 946 void 947 ami_start_xs(struct ami_softc *sc, struct ami_ccb *ccb, struct scsi_xfer *xs) 948 { 949 if (xs->flags & SCSI_POLL) 950 ami_complete(sc, ccb, xs->timeout); 951 else 952 ami_start(sc, ccb); 953 } 954 955 void 956 ami_start(struct ami_softc *sc, struct ami_ccb *ccb) 957 { 958 mtx_enter(&sc->sc_cmd_mtx); 959 ccb->ccb_state = AMI_CCB_PREQUEUED; 960 TAILQ_INSERT_TAIL(&sc->sc_ccb_preq, ccb, ccb_link); 961 mtx_leave(&sc->sc_cmd_mtx); 962 963 ami_runqueue(sc); 964 } 965 966 void 967 ami_runqueue_tick(void *arg) 968 { 969 ami_runqueue(arg); 970 } 971 972 void 973 ami_runqueue(struct ami_softc *sc) 974 { 975 struct ami_ccb *ccb; 976 int add = 0; 977 978 mtx_enter(&sc->sc_cmd_mtx); 979 if (!sc->sc_drainio) { 980 while ((ccb = TAILQ_FIRST(&sc->sc_ccb_preq)) != NULL) { 981 if (sc->sc_exec(sc, &ccb->ccb_cmd) != 0) { 982 add = 1; 983 break; 984 } 985 986 TAILQ_REMOVE(&sc->sc_ccb_preq, ccb, ccb_link); 987 ccb->ccb_state = AMI_CCB_QUEUED; 988 TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); 989 } 990 } 991 mtx_leave(&sc->sc_cmd_mtx); 992 993 if (add) 994 timeout_add(&sc->sc_run_tmo, 1); 995 } 996 997 int 998 ami_poll(struct ami_softc *sc, struct ami_ccb *ccb) 999 { 1000 int error; 1001 1002 mtx_enter(&sc->sc_cmd_mtx); 1003 error = sc->sc_poll(sc, &ccb->ccb_cmd); 1004 if (error == -1) 1005 ccb->ccb_flags |= AMI_CCB_F_ERR; 1006 mtx_leave(&sc->sc_cmd_mtx); 1007 1008 ccb->ccb_done(sc, ccb); 1009 1010 return (error); 1011 } 1012 1013 void 1014 ami_complete(struct ami_softc *sc, struct ami_ccb *ccb, int timeout) 1015 { 1016 void (*done)(struct ami_softc *, struct ami_ccb *); 1017 int ready; 1018 int i = 0; 1019 int s; 1020 1021 done = ccb->ccb_done; 1022 ccb->ccb_done = ami_done_dummy; 1023 1024 /* 1025 * since exec will return if the mbox is busy we have to busy wait 1026 * ourselves. once its in, jam it into the runq. 1027 */ 1028 mtx_enter(&sc->sc_cmd_mtx); 1029 while (i < AMI_MAX_BUSYWAIT) { 1030 if (sc->sc_exec(sc, &ccb->ccb_cmd) == 0) { 1031 ccb->ccb_state = AMI_CCB_QUEUED; 1032 TAILQ_INSERT_TAIL(&sc->sc_ccb_runq, ccb, ccb_link); 1033 break; 1034 } 1035 DELAY(1000); 1036 i++; 1037 } 1038 ready = (ccb->ccb_state == AMI_CCB_QUEUED); 1039 mtx_leave(&sc->sc_cmd_mtx); 1040 1041 if (!ready) { 1042 ccb->ccb_flags |= AMI_CCB_F_ERR; 1043 ccb->ccb_state = AMI_CCB_READY; 1044 goto done; 1045 } 1046 1047 /* 1048 * Override timeout for PERC3. The first command triggers a chip 1049 * reset on the QL12160 chip which causes the firmware to reload. 1050 * 30000 is slightly less than double of how long it takes for the 1051 * firmware to be up again. After the first two commands the 1052 * timeouts are as expected. 1053 */ 1054 timeout = MAX(30000, timeout); /* timeout */ 1055 1056 while (ccb->ccb_state == AMI_CCB_QUEUED) { 1057 s = splbio(); /* interrupt handlers are called at their IPL */ 1058 ready = ami_intr(sc); 1059 splx(s); 1060 1061 if (ready == 0) { 1062 if (timeout-- == 0) { 1063 /* XXX */ 1064 printf("%s: timeout\n", DEVNAME(sc)); 1065 return; 1066 } 1067 1068 delay(1000); 1069 continue; 1070 } 1071 } 1072 1073 done: 1074 done(sc, ccb); 1075 } 1076 1077 void 1078 ami_done_pt(struct ami_softc *sc, struct ami_ccb *ccb) 1079 { 1080 struct scsi_xfer *xs = ccb->ccb_xs; 1081 struct scsi_link *link = xs->sc_link; 1082 struct ami_rawsoftc *rsc = link->adapter_softc; 1083 u_int8_t target = link->target, type; 1084 1085 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1086 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1087 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1088 1089 if (xs->data != NULL) { 1090 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1091 ccb->ccb_dmamap->dm_mapsize, 1092 (xs->flags & SCSI_DATA_IN) ? 1093 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1094 1095 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1096 } 1097 1098 xs->resid = 0; 1099 1100 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1101 xs->error = XS_DRIVER_STUFFUP; 1102 else if (ccb->ccb_status != 0x00) 1103 xs->error = XS_DRIVER_STUFFUP; 1104 else if (xs->flags & SCSI_POLL && xs->cmd->opcode == INQUIRY) { 1105 type = ((struct scsi_inquiry_data *)xs->data)->device & 1106 SID_TYPE; 1107 if (!(type == T_PROCESSOR || type == T_ENCLOSURE)) 1108 xs->error = XS_DRIVER_STUFFUP; 1109 else 1110 rsc->sc_proctarget = target; 1111 } 1112 1113 scsi_done(xs); 1114 } 1115 1116 void 1117 ami_done_xs(struct ami_softc *sc, struct ami_ccb *ccb) 1118 { 1119 struct scsi_xfer *xs = ccb->ccb_xs; 1120 1121 if (xs->data != NULL) { 1122 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1123 ccb->ccb_dmamap->dm_mapsize, 1124 (xs->flags & SCSI_DATA_IN) ? 1125 BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE); 1126 1127 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1128 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1129 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1130 1131 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1132 } 1133 1134 xs->resid = 0; 1135 1136 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1137 xs->error = XS_DRIVER_STUFFUP; 1138 1139 scsi_done(xs); 1140 } 1141 1142 void 1143 ami_done_flush(struct ami_softc *sc, struct ami_ccb *ccb) 1144 { 1145 struct scsi_xfer *xs = ccb->ccb_xs; 1146 struct ami_iocmd *cmd = &ccb->ccb_cmd; 1147 1148 if (ccb->ccb_flags & AMI_CCB_F_ERR) { 1149 xs->error = XS_DRIVER_STUFFUP; 1150 xs->resid = 0; 1151 1152 scsi_done(xs); 1153 return; 1154 } 1155 1156 /* reuse the ccb for the sysflush command */ 1157 ccb->ccb_done = ami_done_sysflush; 1158 cmd->acc_cmd = AMI_SYSFLUSH; 1159 1160 ami_start_xs(sc, ccb, xs); 1161 } 1162 1163 void 1164 ami_done_sysflush(struct ami_softc *sc, struct ami_ccb *ccb) 1165 { 1166 struct scsi_xfer *xs = ccb->ccb_xs; 1167 1168 xs->resid = 0; 1169 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1170 xs->error = XS_DRIVER_STUFFUP; 1171 1172 scsi_done(xs); 1173 } 1174 1175 void 1176 ami_done_dummy(struct ami_softc *sc, struct ami_ccb *ccb) 1177 { 1178 } 1179 1180 void 1181 ami_done_ioctl(struct ami_softc *sc, struct ami_ccb *ccb) 1182 { 1183 wakeup(ccb); 1184 } 1185 1186 void 1187 ami_done_init(struct ami_softc *sc, struct ami_ccb *ccb) 1188 { 1189 /* the ccb is going to be reused, so do nothing with it */ 1190 } 1191 1192 void 1193 ami_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size) 1194 { 1195 size_t copy_cnt; 1196 1197 AMI_DPRINTF(AMI_D_MISC, ("ami_copy_internal_data ")); 1198 1199 if (!xs->datalen) 1200 printf("uio move not yet supported\n"); 1201 else { 1202 copy_cnt = MIN(size, xs->datalen); 1203 bcopy(v, xs->data, copy_cnt); 1204 } 1205 } 1206 1207 void 1208 ami_scsi_raw_cmd(struct scsi_xfer *xs) 1209 { 1210 struct scsi_link *link = xs->sc_link; 1211 struct ami_rawsoftc *rsc = link->adapter_softc; 1212 struct ami_softc *sc = rsc->sc_softc; 1213 u_int8_t channel = rsc->sc_channel, target = link->target; 1214 struct ami_ccb *ccb; 1215 1216 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_raw_cmd ")); 1217 1218 if (xs->cmdlen > AMI_MAX_CDB) { 1219 AMI_DPRINTF(AMI_D_CMD, ("CDB too big %p ", xs)); 1220 bzero(&xs->sense, sizeof(xs->sense)); 1221 xs->sense.error_code = SSD_ERRCODE_VALID | SSD_ERRCODE_CURRENT; 1222 xs->sense.flags = SKEY_ILLEGAL_REQUEST; 1223 xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */ 1224 xs->error = XS_SENSE; 1225 scsi_done(xs); 1226 return; 1227 } 1228 1229 xs->error = XS_NOERROR; 1230 1231 ccb = xs->io; 1232 1233 memset(ccb->ccb_pt, 0, sizeof(struct ami_passthrough)); 1234 1235 ccb->ccb_xs = xs; 1236 ccb->ccb_done = ami_done_pt; 1237 1238 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1239 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1240 1241 ccb->ccb_pt->apt_param = AMI_PTPARAM(AMI_TIMEOUT_6,1,0); 1242 ccb->ccb_pt->apt_channel = channel; 1243 ccb->ccb_pt->apt_target = target; 1244 bcopy(xs->cmd, ccb->ccb_pt->apt_cdb, AMI_MAX_CDB); 1245 ccb->ccb_pt->apt_ncdb = xs->cmdlen; 1246 ccb->ccb_pt->apt_nsense = AMI_MAX_SENSE; 1247 ccb->ccb_pt->apt_datalen = xs->datalen; 1248 ccb->ccb_pt->apt_data = 0; 1249 1250 if (ami_load_ptmem(sc, ccb, xs->data, xs->datalen, 1251 xs->flags & SCSI_DATA_IN, xs->flags & SCSI_NOSLEEP) != 0) { 1252 xs->error = XS_DRIVER_STUFFUP; 1253 scsi_done(xs); 1254 return; 1255 } 1256 1257 ami_start_xs(sc, ccb, xs); 1258 } 1259 1260 int 1261 ami_load_ptmem(struct ami_softc *sc, struct ami_ccb *ccb, void *data, 1262 size_t len, int read, int nowait) 1263 { 1264 bus_dmamap_t dmap = ccb->ccb_dmamap; 1265 bus_dma_segment_t *sgd; 1266 int error, i; 1267 1268 if (data != NULL) { 1269 error = bus_dmamap_load(sc->sc_dmat, dmap, data, len, NULL, 1270 nowait ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1271 if (error) { 1272 if (error == EFBIG) 1273 printf("more than %d dma segs\n", 1274 AMI_MAXOFFSETS); 1275 else 1276 printf("error %d loading dma map\n", error); 1277 1278 return (1); 1279 } 1280 1281 sgd = dmap->dm_segs; 1282 if (dmap->dm_nsegs > 1) { 1283 struct ami_sgent *sgl = ccb->ccb_sglist; 1284 1285 ccb->ccb_pt->apt_nsge = dmap->dm_nsegs; 1286 ccb->ccb_pt->apt_data = ccb->ccb_sglistpa; 1287 1288 for (i = 0; i < dmap->dm_nsegs; i++) { 1289 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1290 sgl[i].asg_len = htole32(sgd[i].ds_len); 1291 } 1292 } else { 1293 ccb->ccb_pt->apt_nsge = 0; 1294 ccb->ccb_pt->apt_data = htole32(sgd->ds_addr); 1295 } 1296 1297 bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize, 1298 read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1299 } 1300 1301 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1302 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1303 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1304 1305 return (0); 1306 } 1307 1308 void 1309 ami_scsi_cmd(struct scsi_xfer *xs) 1310 { 1311 struct scsi_link *link = xs->sc_link; 1312 struct ami_softc *sc = link->adapter_softc; 1313 struct device *dev = link->device_softc; 1314 struct ami_ccb *ccb; 1315 struct ami_iocmd *cmd; 1316 struct scsi_inquiry_data inq; 1317 struct scsi_sense_data sd; 1318 struct scsi_read_cap_data rcd; 1319 u_int8_t target = link->target; 1320 u_int32_t blockno, blockcnt; 1321 struct scsi_rw *rw; 1322 struct scsi_rw_big *rwb; 1323 bus_dma_segment_t *sgd; 1324 int error; 1325 int i; 1326 1327 AMI_DPRINTF(AMI_D_CMD, ("ami_scsi_cmd ")); 1328 1329 if (target >= sc->sc_nunits || !sc->sc_hdr[target].hd_present || 1330 link->lun != 0) { 1331 AMI_DPRINTF(AMI_D_CMD, ("no target %d ", target)); 1332 /* XXX should be XS_SENSE and sense filled out */ 1333 xs->error = XS_DRIVER_STUFFUP; 1334 scsi_done(xs); 1335 return; 1336 } 1337 1338 xs->error = XS_NOERROR; 1339 1340 switch (xs->cmd->opcode) { 1341 case READ_COMMAND: 1342 case READ_BIG: 1343 case WRITE_COMMAND: 1344 case WRITE_BIG: 1345 /* deal with io outside the switch */ 1346 break; 1347 1348 case SYNCHRONIZE_CACHE: 1349 ccb = xs->io; 1350 1351 ccb->ccb_xs = xs; 1352 ccb->ccb_done = ami_done_flush; 1353 if (xs->timeout < 30000) 1354 xs->timeout = 30000; /* at least 30sec */ 1355 1356 cmd = &ccb->ccb_cmd; 1357 cmd->acc_cmd = AMI_FLUSH; 1358 1359 ami_start_xs(sc, ccb, xs); 1360 return; 1361 1362 case TEST_UNIT_READY: 1363 /* save off sd? after autoconf */ 1364 if (!cold) /* XXX bogus */ 1365 strlcpy(sc->sc_hdr[target].dev, dev->dv_xname, 1366 sizeof(sc->sc_hdr[target].dev)); 1367 case START_STOP: 1368 #if 0 1369 case VERIFY: 1370 #endif 1371 case PREVENT_ALLOW: 1372 AMI_DPRINTF(AMI_D_CMD, ("opc %d tgt %d ", xs->cmd->opcode, 1373 target)); 1374 xs->error = XS_NOERROR; 1375 scsi_done(xs); 1376 return; 1377 1378 case REQUEST_SENSE: 1379 AMI_DPRINTF(AMI_D_CMD, ("REQUEST SENSE tgt %d ", target)); 1380 bzero(&sd, sizeof(sd)); 1381 sd.error_code = SSD_ERRCODE_CURRENT; 1382 sd.segment = 0; 1383 sd.flags = SKEY_NO_SENSE; 1384 *(u_int32_t*)sd.info = htole32(0); 1385 sd.extra_len = 0; 1386 ami_copy_internal_data(xs, &sd, sizeof(sd)); 1387 1388 xs->error = XS_NOERROR; 1389 scsi_done(xs); 1390 return; 1391 1392 case INQUIRY: 1393 if (ISSET(((struct scsi_inquiry *)xs->cmd)->flags, SI_EVPD)) { 1394 xs->error = XS_DRIVER_STUFFUP; 1395 scsi_done(xs); 1396 return; 1397 } 1398 1399 AMI_DPRINTF(AMI_D_CMD, ("INQUIRY tgt %d ", target)); 1400 bzero(&inq, sizeof(inq)); 1401 inq.device = T_DIRECT; 1402 inq.dev_qual2 = 0; 1403 inq.version = 2; 1404 inq.response_format = 2; 1405 inq.additional_length = 32; 1406 inq.flags |= SID_CmdQue; 1407 strlcpy(inq.vendor, "AMI ", sizeof(inq.vendor)); 1408 snprintf(inq.product, sizeof(inq.product), 1409 "Host drive #%02d", target); 1410 strlcpy(inq.revision, " ", sizeof(inq.revision)); 1411 ami_copy_internal_data(xs, &inq, sizeof(inq)); 1412 1413 xs->error = XS_NOERROR; 1414 scsi_done(xs); 1415 return; 1416 1417 case READ_CAPACITY: 1418 AMI_DPRINTF(AMI_D_CMD, ("READ CAPACITY tgt %d ", target)); 1419 bzero(&rcd, sizeof(rcd)); 1420 _lto4b(sc->sc_hdr[target].hd_size - 1, rcd.addr); 1421 _lto4b(AMI_SECTOR_SIZE, rcd.length); 1422 ami_copy_internal_data(xs, &rcd, sizeof(rcd)); 1423 1424 xs->error = XS_NOERROR; 1425 scsi_done(xs); 1426 return; 1427 1428 default: 1429 AMI_DPRINTF(AMI_D_CMD, ("unsupported scsi command %#x tgt %d ", 1430 xs->cmd->opcode, target)); 1431 1432 xs->error = XS_DRIVER_STUFFUP; 1433 scsi_done(xs); 1434 return; 1435 } 1436 1437 /* A read or write operation. */ 1438 if (xs->cmdlen == 6) { 1439 rw = (struct scsi_rw *)xs->cmd; 1440 blockno = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff); 1441 blockcnt = rw->length ? rw->length : 0x100; 1442 } else { 1443 rwb = (struct scsi_rw_big *)xs->cmd; 1444 blockno = _4btol(rwb->addr); 1445 blockcnt = _2btol(rwb->length); 1446 } 1447 1448 if (blockno >= sc->sc_hdr[target].hd_size || 1449 blockno + blockcnt > sc->sc_hdr[target].hd_size) { 1450 printf("%s: out of bounds %u-%u >= %u\n", DEVNAME(sc), 1451 blockno, blockcnt, sc->sc_hdr[target].hd_size); 1452 xs->error = XS_DRIVER_STUFFUP; 1453 scsi_done(xs); 1454 return; 1455 } 1456 1457 ccb = xs->io; 1458 1459 ccb->ccb_xs = xs; 1460 ccb->ccb_done = ami_done_xs; 1461 1462 cmd = &ccb->ccb_cmd; 1463 cmd->acc_cmd = (xs->flags & SCSI_DATA_IN) ? AMI_READ : AMI_WRITE; 1464 cmd->acc_mbox.amb_nsect = htole16(blockcnt); 1465 cmd->acc_mbox.amb_lba = htole32(blockno); 1466 cmd->acc_mbox.amb_ldn = target; 1467 1468 error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap, 1469 xs->data, xs->datalen, NULL, 1470 (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); 1471 if (error) { 1472 if (error == EFBIG) 1473 printf("more than %d dma segs\n", AMI_MAXOFFSETS); 1474 else 1475 printf("error %d loading dma map\n", error); 1476 1477 xs->error = XS_DRIVER_STUFFUP; 1478 scsi_done(xs); 1479 return; 1480 } 1481 1482 sgd = ccb->ccb_dmamap->dm_segs; 1483 if (ccb->ccb_dmamap->dm_nsegs > 1) { 1484 struct ami_sgent *sgl = ccb->ccb_sglist; 1485 1486 cmd->acc_mbox.amb_nsge = ccb->ccb_dmamap->dm_nsegs; 1487 cmd->acc_mbox.amb_data = ccb->ccb_sglistpa; 1488 1489 for (i = 0; i < ccb->ccb_dmamap->dm_nsegs; i++) { 1490 sgl[i].asg_addr = htole32(sgd[i].ds_addr); 1491 sgl[i].asg_len = htole32(sgd[i].ds_len); 1492 } 1493 } else { 1494 cmd->acc_mbox.amb_nsge = 0; 1495 cmd->acc_mbox.amb_data = htole32(sgd->ds_addr); 1496 } 1497 1498 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1499 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1500 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); 1501 1502 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1503 ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ? 1504 BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE); 1505 1506 ami_start_xs(sc, ccb, xs); 1507 } 1508 1509 int 1510 ami_intr(void *v) 1511 { 1512 struct ami_iocmd mbox; 1513 struct ami_softc *sc = v; 1514 struct ami_ccb *ccb; 1515 int i, rv = 0, ready; 1516 1517 mtx_enter(&sc->sc_cmd_mtx); 1518 while (!TAILQ_EMPTY(&sc->sc_ccb_runq) && sc->sc_done(sc, &mbox)) { 1519 AMI_DPRINTF(AMI_D_CMD, ("got#%d ", mbox.acc_nstat)); 1520 for (i = 0; i < mbox.acc_nstat; i++ ) { 1521 ready = mbox.acc_cmplidl[i] - 1; 1522 AMI_DPRINTF(AMI_D_CMD, ("ready=%d ", ready)); 1523 1524 ccb = &sc->sc_ccbs[ready]; 1525 ccb->ccb_status = mbox.acc_status; 1526 ccb->ccb_state = AMI_CCB_READY; 1527 TAILQ_REMOVE(&ccb->ccb_sc->sc_ccb_runq, ccb, ccb_link); 1528 1529 mtx_leave(&sc->sc_cmd_mtx); 1530 ccb->ccb_done(sc, ccb); 1531 mtx_enter(&sc->sc_cmd_mtx); 1532 1533 rv = 1; 1534 } 1535 } 1536 ready = (sc->sc_drainio && TAILQ_EMPTY(&sc->sc_ccb_runq)); 1537 mtx_leave(&sc->sc_cmd_mtx); 1538 1539 if (ready) 1540 wakeup(sc); 1541 else if (rv) 1542 ami_runqueue(sc); 1543 1544 AMI_DPRINTF(AMI_D_INTR, ("exit ")); 1545 return (rv); 1546 } 1547 1548 int 1549 ami_scsi_ioctl(struct scsi_link *link, u_long cmd, caddr_t addr, int flag) 1550 { 1551 struct ami_softc *sc = (struct ami_softc *)link->adapter_softc; 1552 /* struct device *dev = (struct device *)link->device_softc; */ 1553 /* u_int8_t target = link->target; */ 1554 1555 if (sc->sc_ioctl) 1556 return (sc->sc_ioctl(link->adapter_softc, cmd, addr)); 1557 else 1558 return (ENOTTY); 1559 } 1560 1561 #if NBIO > 0 1562 int 1563 ami_ioctl(struct device *dev, u_long cmd, caddr_t addr) 1564 { 1565 struct ami_softc *sc = (struct ami_softc *)dev; 1566 int error = 0; 1567 1568 AMI_DPRINTF(AMI_D_IOCTL, ("%s: ioctl ", DEVNAME(sc))); 1569 1570 if (sc->sc_flags & AMI_BROKEN) 1571 return (ENODEV); /* can't do this to broken device for now */ 1572 1573 switch (cmd) { 1574 case BIOCINQ: 1575 AMI_DPRINTF(AMI_D_IOCTL, ("inq ")); 1576 error = ami_ioctl_inq(sc, (struct bioc_inq *)addr); 1577 break; 1578 1579 case BIOCVOL: 1580 AMI_DPRINTF(AMI_D_IOCTL, ("vol ")); 1581 error = ami_ioctl_vol(sc, (struct bioc_vol *)addr); 1582 break; 1583 1584 case BIOCDISK: 1585 AMI_DPRINTF(AMI_D_IOCTL, ("disk ")); 1586 error = ami_ioctl_disk(sc, (struct bioc_disk *)addr); 1587 break; 1588 1589 case BIOCALARM: 1590 AMI_DPRINTF(AMI_D_IOCTL, ("alarm ")); 1591 error = ami_ioctl_alarm(sc, (struct bioc_alarm *)addr); 1592 break; 1593 1594 case BIOCSETSTATE: 1595 AMI_DPRINTF(AMI_D_IOCTL, ("setstate ")); 1596 error = ami_ioctl_setstate(sc, (struct bioc_setstate *)addr); 1597 break; 1598 1599 default: 1600 AMI_DPRINTF(AMI_D_IOCTL, (" invalid ioctl\n")); 1601 error = ENOTTY; 1602 } 1603 1604 return (error); 1605 } 1606 1607 int 1608 ami_drv_pt(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t *cmd, 1609 int clen, int blen, void *buf) 1610 { 1611 struct ami_ccb *ccb; 1612 struct ami_passthrough *pt; 1613 int error = 0; 1614 1615 rw_enter_write(&sc->sc_lock); 1616 1617 ccb = scsi_io_get(&sc->sc_iopool, 0); 1618 if (ccb == NULL) { 1619 error = ENOMEM; 1620 goto err; 1621 } 1622 1623 ccb->ccb_done = ami_done_ioctl; 1624 1625 ccb->ccb_cmd.acc_cmd = AMI_PASSTHRU; 1626 ccb->ccb_cmd.acc_passthru.apt_data = ccb->ccb_ptpa; 1627 1628 pt = ccb->ccb_pt; 1629 memset(pt, 0, sizeof *pt); 1630 pt->apt_channel = ch; 1631 pt->apt_target = tg; 1632 pt->apt_ncdb = clen; 1633 pt->apt_nsense = sizeof(struct scsi_sense_data); 1634 pt->apt_datalen = blen; 1635 pt->apt_data = 0; 1636 1637 bcopy(cmd, pt->apt_cdb, clen); 1638 1639 if (ami_load_ptmem(sc, ccb, buf, blen, 1, 0) != 0) { 1640 error = ENOMEM; 1641 goto ptmemerr; 1642 } 1643 1644 ami_start(sc, ccb); 1645 1646 while (ccb->ccb_state != AMI_CCB_READY) 1647 tsleep_nsec(ccb, PRIBIO, "ami_drv_pt", INFSLP); 1648 1649 bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap, 0, 1650 ccb->ccb_dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD); 1651 bus_dmamap_sync(sc->sc_dmat, AMIMEM_MAP(sc->sc_ccbmem_am), 1652 ccb->ccb_offset, sizeof(struct ami_ccbmem), 1653 BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); 1654 bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap); 1655 1656 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1657 error = EIO; 1658 else if (pt->apt_scsistat != 0x00) 1659 error = EIO; 1660 1661 ptmemerr: 1662 scsi_io_put(&sc->sc_iopool, ccb); 1663 1664 err: 1665 rw_exit_write(&sc->sc_lock); 1666 return (error); 1667 } 1668 1669 int 1670 ami_drv_inq(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, u_int8_t page, 1671 void *inqbuf) 1672 { 1673 struct scsi_inquiry_data *inq = inqbuf; 1674 u_int8_t cdb[6]; 1675 int error = 0; 1676 1677 bzero(&cdb, sizeof cdb); 1678 1679 cdb[0] = INQUIRY; 1680 cdb[1] = 0; 1681 cdb[2] = 0; 1682 cdb[3] = 0; 1683 cdb[4] = sizeof(struct scsi_inquiry_data); 1684 cdb[5] = 0; 1685 if (page != 0) { 1686 cdb[1] = SI_EVPD; 1687 cdb[2] = page; 1688 } 1689 1690 error = ami_drv_pt(sc, ch, tg, cdb, 6, sizeof *inq, inqbuf); 1691 if (error) 1692 return (error); 1693 1694 if ((inq->device & SID_TYPE) != T_DIRECT) 1695 error = EINVAL; 1696 1697 return (error); 1698 } 1699 1700 int 1701 ami_drv_readcap(struct ami_softc *sc, u_int8_t ch, u_int8_t tg, daddr_t *sz) 1702 { 1703 struct scsi_read_cap_data *rcd = NULL; 1704 struct scsi_read_cap_data_16 *rcd16 = NULL; 1705 u_int8_t cdb[16]; 1706 u_int32_t blksz; 1707 daddr_t noblk; 1708 int error = 0; 1709 1710 bzero(&cdb, sizeof cdb); 1711 cdb[0] = READ_CAPACITY; 1712 rcd = dma_alloc(sizeof(*rcd), PR_WAITOK); 1713 1714 error = ami_drv_pt(sc, ch, tg, cdb, 10, sizeof(*rcd), rcd); 1715 if (error) 1716 goto fail; 1717 1718 noblk = _4btol(rcd->addr); 1719 if (noblk == 0xffffffffllu) { 1720 /* huge disk */ 1721 bzero(&cdb, sizeof cdb); 1722 cdb[0] = READ_CAPACITY_16; 1723 rcd16 = dma_alloc(sizeof(*rcd16), PR_WAITOK); 1724 1725 error = ami_drv_pt(sc, ch, tg, cdb, 16, sizeof(*rcd16), rcd16); 1726 if (error) 1727 goto fail; 1728 1729 noblk = _8btol(rcd16->addr); 1730 blksz = _4btol(rcd16->length); 1731 } else 1732 blksz = _4btol(rcd->length); 1733 1734 if (blksz == 0) 1735 blksz = 512; 1736 *sz = noblk * blksz; 1737 1738 fail: 1739 if (rcd16) 1740 dma_free(rcd16, sizeof(*rcd16)); 1741 dma_free(rcd, sizeof(*rcd)); 1742 return (error); 1743 } 1744 1745 int 1746 ami_mgmt(struct ami_softc *sc, u_int8_t opcode, u_int8_t par1, u_int8_t par2, 1747 u_int8_t par3, size_t size, void *buffer) 1748 { 1749 struct ami_ccb *ccb; 1750 struct ami_iocmd *cmd; 1751 struct ami_mem *am = NULL; 1752 char *idata = NULL; 1753 int error = 0; 1754 1755 rw_enter_write(&sc->sc_lock); 1756 1757 if (opcode != AMI_CHSTATE) { 1758 ccb = scsi_io_get(&sc->sc_iopool, 0); 1759 if (ccb == NULL) { 1760 error = ENOMEM; 1761 goto err; 1762 } 1763 ccb->ccb_done = ami_done_ioctl; 1764 } else 1765 ccb = sc->sc_mgmtccb; 1766 1767 if (size) { 1768 if ((am = ami_allocmem(sc, size)) == NULL) { 1769 error = ENOMEM; 1770 goto memerr; 1771 } 1772 idata = AMIMEM_KVA(am); 1773 } 1774 1775 cmd = &ccb->ccb_cmd; 1776 cmd->acc_cmd = opcode; 1777 1778 /* 1779 * some commands require data to be written to idata before sending 1780 * command to fw 1781 */ 1782 switch (opcode) { 1783 case AMI_SPEAKER: 1784 *idata = par1; 1785 break; 1786 default: 1787 cmd->acc_io.aio_channel = par1; 1788 cmd->acc_io.aio_param = par2; 1789 cmd->acc_io.aio_pad[0] = par3; 1790 break; 1791 }; 1792 1793 cmd->acc_io.aio_data = am ? htole32(AMIMEM_DVA(am)) : 0; 1794 1795 if (opcode != AMI_CHSTATE) { 1796 ami_start(sc, ccb); 1797 mtx_enter(&sc->sc_cmd_mtx); 1798 while (ccb->ccb_state != AMI_CCB_READY) 1799 msleep_nsec(ccb, &sc->sc_cmd_mtx, PRIBIO, "ami_mgmt", 1800 INFSLP); 1801 mtx_leave(&sc->sc_cmd_mtx); 1802 } else { 1803 /* change state must be run with id 0xfe and MUST be polled */ 1804 mtx_enter(&sc->sc_cmd_mtx); 1805 sc->sc_drainio = 1; 1806 while (!TAILQ_EMPTY(&sc->sc_ccb_runq)) { 1807 if (msleep_nsec(sc, &sc->sc_cmd_mtx, PRIBIO, 1808 "amimgmt", SEC_TO_NSEC(60)) == EWOULDBLOCK) { 1809 printf("%s: drain io timeout\n", DEVNAME(sc)); 1810 ccb->ccb_flags |= AMI_CCB_F_ERR; 1811 goto restartio; 1812 } 1813 } 1814 1815 error = sc->sc_poll(sc, &ccb->ccb_cmd); 1816 if (error == -1) 1817 ccb->ccb_flags |= AMI_CCB_F_ERR; 1818 1819 restartio: 1820 /* restart io */ 1821 sc->sc_drainio = 0; 1822 mtx_leave(&sc->sc_cmd_mtx); 1823 ami_runqueue(sc); 1824 } 1825 1826 if (ccb->ccb_flags & AMI_CCB_F_ERR) 1827 error = EIO; 1828 else if (buffer && size) 1829 memcpy(buffer, idata, size); 1830 1831 if (am) 1832 ami_freemem(sc, am); 1833 memerr: 1834 if (opcode != AMI_CHSTATE) { 1835 scsi_io_put(&sc->sc_iopool, ccb); 1836 } else { 1837 ccb->ccb_flags = 0; 1838 ccb->ccb_state = AMI_CCB_FREE; 1839 } 1840 1841 err: 1842 rw_exit_write(&sc->sc_lock); 1843 return (error); 1844 } 1845 1846 int 1847 ami_ioctl_inq(struct ami_softc *sc, struct bioc_inq *bi) 1848 { 1849 struct ami_big_diskarray *p; /* struct too large for stack */ 1850 struct scsi_inquiry_data *inqbuf; 1851 struct ami_fc_einquiry einq; 1852 int ch, tg; 1853 int i, s, t, off; 1854 int error = 0, changes = 0; 1855 1856 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_EINQ3, 1857 AMI_FC_EINQ3_SOLICITED_FULL, 0, sizeof einq, &einq))) 1858 return (EINVAL); 1859 1860 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 1861 1862 if (einq.ain_drvinscnt == sc->sc_drvinscnt) { 1863 /* poke existing known drives to make sure they aren't gone */ 1864 for(i = 0; i < sc->sc_channels * 16; i++) { 1865 if (sc->sc_plist[i] == 0) 1866 continue; 1867 1868 ch = (i & 0xf0) >> 4; 1869 tg = i & 0x0f; 1870 if (ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 1871 /* drive is gone, force rescan */ 1872 changes = 1; 1873 break; 1874 } 1875 } 1876 if (changes == 0) { 1877 bcopy(&sc->sc_bi, bi, sizeof *bi); 1878 goto done; 1879 } 1880 } 1881 1882 sc->sc_drvinscnt = einq.ain_drvinscnt; 1883 1884 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 1885 if (!p) { 1886 error = ENOMEM; 1887 goto done; 1888 } 1889 1890 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, 1891 p))) { 1892 error = EINVAL; 1893 goto bail; 1894 } 1895 1896 bzero(sc->sc_plist, sizeof sc->sc_plist); 1897 1898 bi->bi_novol = p->ada_nld; 1899 bi->bi_nodisk = 0; 1900 strlcpy(bi->bi_dev, DEVNAME(sc), sizeof(bi->bi_dev)); 1901 1902 /* count used disks, including failed ones */ 1903 for (i = 0; i < p->ada_nld; i++) 1904 for (s = 0; s < p->ald[i].adl_spandepth; s++) 1905 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 1906 off = p->ald[i].asp[s].adv[t].add_channel * 1907 AMI_MAX_TARGET + 1908 p->ald[i].asp[s].adv[t].add_target; 1909 1910 /* account for multi raid vol on same disk */ 1911 if (!sc->sc_plist[off]) { 1912 sc->sc_plist[off] = 1; 1913 bi->bi_nodisk++; 1914 } 1915 } 1916 1917 /* count unsued disks */ 1918 for(i = 0; i < sc->sc_channels * 16; i++) { 1919 if (sc->sc_plist[i]) 1920 continue; /* skip claimed drives */ 1921 1922 /* 1923 * hack to invalidate device type, needed for initiator id 1924 * on an unconnected channel. 1925 * XXX find out if we can determine this differently 1926 */ 1927 memset(inqbuf, 0xff, sizeof(*inqbuf)); 1928 1929 ch = (i & 0xf0) >> 4; 1930 tg = i & 0x0f; 1931 if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 1932 if ((inqbuf->device & SID_TYPE) != T_DIRECT) 1933 continue; 1934 bi->bi_novol++; 1935 bi->bi_nodisk++; 1936 sc->sc_plist[i] = 2; 1937 } else 1938 sc->sc_plist[i] = 0; 1939 } 1940 1941 bcopy(bi, &sc->sc_bi, sizeof sc->sc_bi); 1942 error = 0; 1943 bail: 1944 free(p, M_DEVBUF, sizeof *p); 1945 done: 1946 dma_free(inqbuf, sizeof(*inqbuf)); 1947 return (error); 1948 } 1949 1950 int 1951 ami_vol(struct ami_softc *sc, struct bioc_vol *bv, struct ami_big_diskarray *p) 1952 { 1953 int i, ld = p->ada_nld, error = EINVAL; 1954 1955 for(i = 0; i < sc->sc_channels * 16; i++) { 1956 /* skip claimed/unused drives */ 1957 if (sc->sc_plist[i] != 2) 1958 continue; 1959 1960 /* are we it? */ 1961 if (ld != bv->bv_volid) { 1962 ld++; 1963 continue; 1964 } 1965 1966 bv->bv_status = BIOC_SVONLINE; 1967 bv->bv_size = (uint64_t)p->apd[i].adp_size * 1968 (uint64_t)512; 1969 bv->bv_nodisk = 1; 1970 strlcpy(bv->bv_dev, 1971 sc->sc_hdr[bv->bv_volid].dev, 1972 sizeof(bv->bv_dev)); 1973 1974 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE 1975 && p->apd[i].adp_type == 0) 1976 bv->bv_level = -1; 1977 else 1978 bv->bv_level = -2; 1979 1980 error = 0; 1981 goto bail; 1982 } 1983 1984 bail: 1985 return (error); 1986 } 1987 1988 int 1989 ami_disk(struct ami_softc *sc, struct bioc_disk *bd, 1990 struct ami_big_diskarray *p) 1991 { 1992 char vend[8+16+4+1], *vendp; 1993 char ser[32 + 1]; 1994 struct scsi_inquiry_data *inqbuf; 1995 struct scsi_vpd_serial *vpdbuf; 1996 int i, ld = p->ada_nld, error = EINVAL; 1997 u_int8_t ch, tg; 1998 daddr_t sz = 0; 1999 2000 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2001 vpdbuf = dma_alloc(sizeof(*vpdbuf), PR_WAITOK); 2002 2003 for(i = 0; i < sc->sc_channels * 16; i++) { 2004 /* skip claimed/unused drives */ 2005 if (sc->sc_plist[i] != 2) 2006 continue; 2007 2008 /* are we it? */ 2009 if (ld != bd->bd_volid) { 2010 ld++; 2011 continue; 2012 } 2013 2014 ch = (i & 0xf0) >> 4; 2015 tg = i & 0x0f; 2016 if (ami_drv_inq(sc, ch, tg, 0, inqbuf)) 2017 goto bail; 2018 2019 vendp = inqbuf->vendor; 2020 bcopy(vendp, vend, sizeof vend - 1); 2021 2022 vend[sizeof vend - 1] = '\0'; 2023 strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor)); 2024 2025 if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) { 2026 bcopy(vpdbuf->serial, ser, sizeof ser - 1); 2027 ser[sizeof ser - 1] = '\0'; 2028 if (_2btol(vpdbuf->hdr.page_length) < sizeof ser) 2029 ser[_2btol(vpdbuf->hdr.page_length)] = '\0'; 2030 strlcpy(bd->bd_serial, ser, sizeof(bd->bd_serial)); 2031 } 2032 2033 error = ami_drv_readcap(sc, ch, tg, &sz); 2034 if (error) 2035 goto bail; 2036 2037 bd->bd_size = sz; 2038 bd->bd_channel = ch; 2039 bd->bd_target = tg; 2040 2041 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2042 sizeof(bd->bd_procdev)); 2043 2044 if (p->apd[i].adp_ostatus == AMI_PD_HOTSPARE) 2045 bd->bd_status = BIOC_SDHOTSPARE; 2046 else 2047 bd->bd_status = BIOC_SDUNUSED; 2048 2049 #ifdef AMI_DEBUG 2050 if (p->apd[i].adp_type != 0) 2051 printf("invalid disk type: %d %d %x inquiry type: %x\n", 2052 ch, tg, p->apd[i].adp_type, inqbuf->device); 2053 #endif /* AMI_DEBUG */ 2054 2055 error = 0; 2056 goto bail; 2057 } 2058 2059 bail: 2060 dma_free(inqbuf, sizeof(*inqbuf)); 2061 dma_free(vpdbuf, sizeof(*vpdbuf)); 2062 return (error); 2063 } 2064 2065 int 2066 ami_ioctl_vol(struct ami_softc *sc, struct bioc_vol *bv) 2067 { 2068 struct ami_big_diskarray *p; /* struct too large for stack */ 2069 int i, s, t, off; 2070 int error = 0; 2071 struct ami_progress perc; 2072 u_int8_t bgi[5]; /* 40 LD, 1 bit per LD if BGI is active */ 2073 2074 p = malloc(sizeof *p, M_DEVBUF, M_NOWAIT); 2075 if (!p) 2076 return (ENOMEM); 2077 2078 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2079 goto bail; 2080 2081 if (bv->bv_volid >= p->ada_nld) { 2082 error = ami_vol(sc, bv, p); 2083 goto bail; 2084 } 2085 2086 i = bv->bv_volid; 2087 2088 switch (p->ald[i].adl_status) { 2089 case AMI_RDRV_OFFLINE: 2090 bv->bv_status = BIOC_SVOFFLINE; 2091 break; 2092 2093 case AMI_RDRV_DEGRADED: 2094 bv->bv_status = BIOC_SVDEGRADED; 2095 break; 2096 2097 case AMI_RDRV_OPTIMAL: 2098 bv->bv_status = BIOC_SVONLINE; 2099 bv->bv_percent = -1; 2100 2101 /* get BGI progress here and over-ride status if so */ 2102 memset(bgi, 0, sizeof bgi); 2103 if (ami_mgmt(sc, AMI_MISC, AMI_GET_BGI, 0, 0, sizeof bgi, &bgi)) 2104 break; 2105 2106 if ((bgi[i / 8] & (1 << i % 8)) == 0) 2107 break; 2108 2109 if (!ami_mgmt(sc, AMI_GCHECKPROGR, i, 0, 0, sizeof perc, &perc)) 2110 if (perc.apr_progress < 100) { 2111 bv->bv_status = BIOC_SVSCRUB; 2112 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2113 perc.apr_progress; 2114 } 2115 break; 2116 2117 default: 2118 bv->bv_status = BIOC_SVINVALID; 2119 } 2120 2121 /* over-ride status if a pd is in rebuild status for this ld */ 2122 for (s = 0; s < p->ald[i].adl_spandepth; s++) 2123 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2124 off = p->ald[i].asp[s].adv[t].add_channel * 2125 AMI_MAX_TARGET + 2126 p->ald[i].asp[s].adv[t].add_target; 2127 2128 if (p->apd[off].adp_ostatus != AMI_PD_RBLD) 2129 continue; 2130 2131 /* get rebuild progress from pd 0 */ 2132 bv->bv_status = BIOC_SVREBUILD; 2133 if (ami_mgmt(sc, AMI_GRBLDPROGR, 2134 p->ald[i].asp[s].adv[t].add_channel, 2135 p->ald[i].asp[s].adv[t].add_target, 0, 2136 sizeof perc, &perc)) 2137 bv->bv_percent = -1; 2138 else 2139 bv->bv_percent = perc.apr_progress >= 100 ? -1 : 2140 perc.apr_progress; 2141 break; 2142 } 2143 2144 bv->bv_size = 0; 2145 bv->bv_level = p->ald[i].adl_raidlvl; 2146 bv->bv_nodisk = 0; 2147 2148 for (s = 0; s < p->ald[i].adl_spandepth; s++) { 2149 for (t = 0; t < p->ald[i].adl_nstripes; t++) 2150 bv->bv_nodisk++; 2151 2152 switch (bv->bv_level) { 2153 case 0: 2154 bv->bv_size += p->ald[i].asp[s].ads_length * 2155 p->ald[i].adl_nstripes; 2156 break; 2157 2158 case 1: 2159 bv->bv_size += p->ald[i].asp[s].ads_length; 2160 break; 2161 2162 case 5: 2163 bv->bv_size += p->ald[i].asp[s].ads_length * 2164 (p->ald[i].adl_nstripes - 1); 2165 break; 2166 } 2167 } 2168 2169 if (p->ald[i].adl_spandepth > 1) 2170 bv->bv_level *= 10; 2171 2172 bv->bv_size *= (uint64_t)512; 2173 2174 strlcpy(bv->bv_dev, sc->sc_hdr[i].dev, sizeof(bv->bv_dev)); 2175 2176 bail: 2177 free(p, M_DEVBUF, sizeof *p); 2178 2179 return (error); 2180 } 2181 2182 int 2183 ami_ioctl_disk(struct ami_softc *sc, struct bioc_disk *bd) 2184 { 2185 struct scsi_inquiry_data *inqbuf; 2186 struct scsi_vpd_serial *vpdbuf; 2187 struct ami_big_diskarray *p; /* struct too large for stack */ 2188 int i, s, t, d; 2189 int off; 2190 int error = EINVAL; 2191 u_int16_t ch, tg; 2192 char vend[8+16+4+1], *vendp; 2193 char ser[32 + 1]; 2194 2195 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2196 vpdbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2197 p = malloc(sizeof *p, M_DEVBUF, M_WAITOK); 2198 2199 if ((error = ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof *p, p))) 2200 goto bail; 2201 2202 if (bd->bd_volid >= p->ada_nld) { 2203 error = ami_disk(sc, bd, p); 2204 goto bail; 2205 } 2206 2207 i = bd->bd_volid; 2208 for (s = 0, d = 0; s < p->ald[i].adl_spandepth; s++) 2209 for (t = 0; t < p->ald[i].adl_nstripes; t++) { 2210 if (d != bd->bd_diskid) { 2211 d++; 2212 continue; 2213 } 2214 2215 off = p->ald[i].asp[s].adv[t].add_channel * 2216 AMI_MAX_TARGET + 2217 p->ald[i].asp[s].adv[t].add_target; 2218 2219 bd->bd_size = (uint64_t)p->apd[off].adp_size * 2220 (uint64_t)512; 2221 2222 switch (p->apd[off].adp_ostatus) { 2223 case AMI_PD_UNCNF: 2224 bd->bd_status = BIOC_SDUNUSED; 2225 break; 2226 2227 case AMI_PD_ONLINE: 2228 bd->bd_status = BIOC_SDONLINE; 2229 break; 2230 2231 case AMI_PD_FAILED: 2232 bd->bd_status = BIOC_SDFAILED; 2233 bd->bd_size = 0; 2234 break; 2235 2236 case AMI_PD_RBLD: 2237 bd->bd_status = BIOC_SDREBUILD; 2238 break; 2239 2240 case AMI_PD_HOTSPARE: 2241 bd->bd_status = BIOC_SDHOTSPARE; 2242 break; 2243 2244 default: 2245 bd->bd_status = BIOC_SDINVALID; 2246 bd->bd_size = 0; 2247 } 2248 2249 2250 ch = p->ald[i].asp[s].adv[t].add_target >> 4; 2251 tg = p->ald[i].asp[s].adv[t].add_target & 0x0f; 2252 2253 bd->bd_channel = ch; 2254 bd->bd_target = tg; 2255 strlcpy(bd->bd_procdev, sc->sc_rawsoftcs[ch].sc_procdev, 2256 sizeof(bd->bd_procdev)); 2257 2258 /* if we are failed don't query drive */ 2259 if (bd->bd_size == 0) { 2260 bzero(&bd->bd_vendor, sizeof(bd->bd_vendor)); 2261 bzero(&bd->bd_serial, sizeof(bd->bd_serial)); 2262 goto done; 2263 } 2264 2265 if (!ami_drv_inq(sc, ch, tg, 0, inqbuf)) { 2266 vendp = inqbuf->vendor; 2267 bcopy(vendp, vend, sizeof vend - 1); 2268 vend[sizeof vend - 1] = '\0'; 2269 strlcpy(bd->bd_vendor, vend, 2270 sizeof(bd->bd_vendor)); 2271 } 2272 2273 if (!ami_drv_inq(sc, ch, tg, 0x80, vpdbuf)) { 2274 bcopy(vpdbuf->serial, ser, sizeof ser - 1); 2275 ser[sizeof ser - 1] = '\0'; 2276 if (_2btol(vpdbuf->hdr.page_length) < 2277 sizeof(ser)) 2278 ser[_2btol(vpdbuf->hdr.page_length)] = 2279 '\0'; 2280 strlcpy(bd->bd_serial, ser, 2281 sizeof(bd->bd_serial)); 2282 } 2283 goto done; 2284 } 2285 2286 done: 2287 error = 0; 2288 bail: 2289 free(p, M_DEVBUF, sizeof *p); 2290 dma_free(vpdbuf, sizeof(*vpdbuf)); 2291 dma_free(inqbuf, sizeof(*inqbuf)); 2292 2293 return (error); 2294 } 2295 2296 int ami_ioctl_alarm(struct ami_softc *sc, struct bioc_alarm *ba) 2297 { 2298 int error = 0; 2299 u_int8_t func, ret; 2300 2301 switch(ba->ba_opcode) { 2302 case BIOC_SADISABLE: 2303 func = AMI_SPKR_OFF; 2304 break; 2305 2306 case BIOC_SAENABLE: 2307 func = AMI_SPKR_ON; 2308 break; 2309 2310 case BIOC_SASILENCE: 2311 func = AMI_SPKR_SHUT; 2312 break; 2313 2314 case BIOC_GASTATUS: 2315 func = AMI_SPKR_GVAL; 2316 break; 2317 2318 case BIOC_SATEST: 2319 func = AMI_SPKR_TEST; 2320 break; 2321 2322 default: 2323 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocalarm invalid opcode %x\n", 2324 DEVNAME(sc), ba->ba_opcode)); 2325 return (EINVAL); 2326 } 2327 2328 if (!(error = ami_mgmt(sc, AMI_SPEAKER, func, 0, 0, sizeof ret, 2329 &ret))) { 2330 if (ba->ba_opcode == BIOC_GASTATUS) 2331 ba->ba_status = ret; 2332 else 2333 ba->ba_status = 0; 2334 } 2335 2336 return (error); 2337 } 2338 2339 int 2340 ami_ioctl_setstate(struct ami_softc *sc, struct bioc_setstate *bs) 2341 { 2342 struct scsi_inquiry_data *inqbuf; 2343 int func, error = 0; 2344 2345 inqbuf = dma_alloc(sizeof(*inqbuf), PR_WAITOK); 2346 2347 switch (bs->bs_status) { 2348 case BIOC_SSONLINE: 2349 func = AMI_STATE_ON; 2350 break; 2351 2352 case BIOC_SSOFFLINE: 2353 func = AMI_STATE_FAIL; 2354 break; 2355 2356 case BIOC_SSHOTSPARE: 2357 if (ami_drv_inq(sc, bs->bs_channel, bs->bs_target, 0, 2358 inqbuf)) { 2359 error = EINVAL; 2360 goto done; 2361 } 2362 2363 func = AMI_STATE_SPARE; 2364 break; 2365 2366 default: 2367 AMI_DPRINTF(AMI_D_IOCTL, ("%s: biocsetstate invalid opcode %x\n" 2368 , DEVNAME(sc), bs->bs_status)); 2369 error = EINVAL; 2370 goto done; 2371 } 2372 2373 if ((error = ami_mgmt(sc, AMI_CHSTATE, bs->bs_channel, bs->bs_target, 2374 func, 0, NULL))) 2375 goto done; 2376 2377 done: 2378 dma_free(inqbuf, sizeof(*inqbuf)); 2379 return (error); 2380 } 2381 2382 #ifndef SMALL_KERNEL 2383 int 2384 ami_create_sensors(struct ami_softc *sc) 2385 { 2386 struct device *dev; 2387 struct scsibus_softc *ssc = NULL; 2388 struct scsi_link *link; 2389 int i; 2390 2391 TAILQ_FOREACH(dev, &alldevs, dv_list) { 2392 if (dev->dv_parent != &sc->sc_dev) 2393 continue; 2394 2395 /* check if this is the scsibus for the logical disks */ 2396 ssc = (struct scsibus_softc *)dev; 2397 if (ssc->adapter_link == &sc->sc_link) 2398 break; 2399 } 2400 2401 if (ssc == NULL) 2402 return (1); 2403 2404 sc->sc_sensors = mallocarray(sc->sc_nunits, sizeof(struct ksensor), 2405 M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO); 2406 if (sc->sc_sensors == NULL) 2407 return (1); 2408 2409 strlcpy(sc->sc_sensordev.xname, DEVNAME(sc), 2410 sizeof(sc->sc_sensordev.xname)); 2411 2412 for (i = 0; i < sc->sc_nunits; i++) { 2413 link = scsi_get_link(ssc, i, 0); 2414 if (link == NULL) 2415 goto bad; 2416 2417 dev = link->device_softc; 2418 2419 sc->sc_sensors[i].type = SENSOR_DRIVE; 2420 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2421 2422 strlcpy(sc->sc_sensors[i].desc, dev->dv_xname, 2423 sizeof(sc->sc_sensors[i].desc)); 2424 2425 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]); 2426 } 2427 2428 sc->sc_bd = malloc(sizeof(*sc->sc_bd), M_DEVBUF, M_WAITOK|M_CANFAIL); 2429 if (sc->sc_bd == NULL) 2430 goto bad; 2431 2432 if (sensor_task_register(sc, ami_refresh_sensors, 10) == NULL) 2433 goto freebd; 2434 2435 sensordev_install(&sc->sc_sensordev); 2436 2437 return (0); 2438 2439 freebd: 2440 free(sc->sc_bd, M_DEVBUF, sizeof(*sc->sc_bd)); 2441 bad: 2442 free(sc->sc_sensors, M_DEVBUF, sc->sc_nunits * sizeof(struct ksensor)); 2443 2444 return (1); 2445 } 2446 2447 void 2448 ami_refresh_sensors(void *arg) 2449 { 2450 struct ami_softc *sc = arg; 2451 int i; 2452 2453 if (ami_mgmt(sc, AMI_FCOP, AMI_FC_RDCONF, 0, 0, sizeof(*sc->sc_bd), 2454 sc->sc_bd)) { 2455 for (i = 0; i < sc->sc_nunits; i++) { 2456 sc->sc_sensors[i].value = 0; /* unknown */ 2457 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2458 } 2459 return; 2460 } 2461 2462 for (i = 0; i < sc->sc_nunits; i++) { 2463 switch (sc->sc_bd->ald[i].adl_status) { 2464 case AMI_RDRV_OFFLINE: 2465 sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL; 2466 sc->sc_sensors[i].status = SENSOR_S_CRIT; 2467 break; 2468 2469 case AMI_RDRV_DEGRADED: 2470 sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL; 2471 sc->sc_sensors[i].status = SENSOR_S_WARN; 2472 break; 2473 2474 case AMI_RDRV_OPTIMAL: 2475 sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE; 2476 sc->sc_sensors[i].status = SENSOR_S_OK; 2477 break; 2478 2479 default: 2480 sc->sc_sensors[i].value = 0; /* unknown */ 2481 sc->sc_sensors[i].status = SENSOR_S_UNKNOWN; 2482 } 2483 } 2484 } 2485 #endif /* SMALL_KERNEL */ 2486 #endif /* NBIO > 0 */ 2487 2488 #ifdef AMI_DEBUG 2489 void 2490 ami_print_mbox(struct ami_iocmd *mbox) 2491 { 2492 int i; 2493 2494 printf("acc_cmd: %d aac_id: %d acc_busy: %d acc_nstat: %d ", 2495 mbox->acc_cmd, mbox->acc_id, mbox->acc_busy, mbox->acc_nstat); 2496 printf("acc_status: %d acc_poll: %d acc_ack: %d\n", 2497 mbox->acc_status, mbox->acc_poll, mbox->acc_ack); 2498 2499 printf("acc_cmplidl: "); 2500 for (i = 0; i < AMI_MAXSTATACK; i++) { 2501 printf("[%d] = %d ", i, mbox->acc_cmplidl[i]); 2502 } 2503 2504 printf("\n"); 2505 } 2506 #endif /* AMI_DEBUG */ 2507