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