Annotation of sys/dev/ic/ami.c, Revision 1.1.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