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