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