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