icp.c revision 1.2 1 /* $NetBSD: icp.c,v 1.2 2002/06/01 23:50:58 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by Niklas Hallqvist.
53 * 4. The name of the author may not be used to endorse or promote products
54 * derived from this software without specific prior written permission.
55 *
56 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
57 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
58 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
59 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
60 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
61 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
62 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
63 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
64 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
65 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
66 *
67 * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
68 */
69
70 /*
71 * This driver would not have written if it was not for the hardware donations
72 * from both ICP-Vortex and ko.neT. I want to thank them for their support.
73 *
74 * Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by
75 * Intel.
76 */
77
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.2 2002/06/01 23:50:58 lukem Exp $");
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/kernel.h>
84 #include <sys/device.h>
85 #include <sys/queue.h>
86 #include <sys/proc.h>
87 #include <sys/buf.h>
88 #include <sys/endian.h>
89 #include <sys/malloc.h>
90 #include <sys/disk.h>
91
92 #include <uvm/uvm_extern.h>
93
94 #include <machine/bswap.h>
95 #include <machine/bus.h>
96
97 #include <dev/pci/pcireg.h>
98 #include <dev/pci/pcivar.h>
99 #include <dev/pci/pcidevs.h>
100
101 #include <dev/ic/icpreg.h>
102 #include <dev/ic/icpvar.h>
103
104 int icp_async_event(struct icp_softc *, int);
105 void icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
106 void icp_chain(struct icp_softc *);
107 int icp_print(void *, const char *);
108 int icp_submatch(struct device *, struct cfdata *, void *);
109 void icp_watchdog(void *);
110
111 int
112 icp_init(struct icp_softc *icp, const char *intrstr)
113 {
114 struct icp_attach_args icpa;
115 struct icp_binfo binfo;
116 struct icp_ccb *ic;
117 u_int16_t cdev_cnt;
118 int i, j, state, feat, nsegs, rv, noscsi, nocache;
119
120 noscsi = 0;
121 nocache = 0;
122
123 if (intrstr != NULL)
124 printf("%s: interrupting at %s\n", icp->icp_dv.dv_xname,
125 intrstr);
126
127 SIMPLEQ_INIT(&icp->icp_ccb_queue);
128 SIMPLEQ_INIT(&icp->icp_ccb_freelist);
129 callout_init(&icp->icp_wdog_callout);
130
131 /*
132 * Allocate a scratch area.
133 */
134 if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
135 ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
136 &icp->icp_scr_dmamap) != 0) {
137 printf("%s: cannot create scratch dmamap\n",
138 icp->icp_dv.dv_xname);
139 return (1);
140 }
141 state++;
142
143 if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
144 icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
145 printf("%s: cannot alloc scratch dmamem\n",
146 icp->icp_dv.dv_xname);
147 goto bail_out;
148 }
149 state++;
150
151 if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
152 ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
153 printf("%s: cannot map scratch dmamem\n", icp->icp_dv.dv_xname);
154 goto bail_out;
155 }
156 state++;
157
158 if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
159 ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
160 printf("%s: cannot load scratch dmamap\n", icp->icp_dv.dv_xname);
161 goto bail_out;
162 }
163 state++;
164
165 /*
166 * Allocate and initialize the command control blocks.
167 */
168 ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
169 if ((icp->icp_ccbs = ic) == NULL) {
170 printf("%s: malloc() failed\n", icp->icp_dv.dv_xname);
171 goto bail_out;
172 }
173 state++;
174
175 for (i = 0; i < ICP_NCCBS; i++, ic++) {
176 /*
177 * The first two command indexes have special meanings, so
178 * we can't use them.
179 */
180 ic->ic_ident = i + 2;
181 rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
182 ICP_MAXSG, ICP_MAX_XFER, 0,
183 BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
184 &ic->ic_xfer_map);
185 if (rv != 0)
186 break;
187 icp->icp_nccbs++;
188 icp_ccb_free(icp, ic);
189 }
190 #ifdef DIAGNOSTIC
191 if (icp->icp_nccbs != ICP_NCCBS)
192 printf("%s: %d/%d CCBs usable\n", icp->icp_dv.dv_xname,
193 icp->icp_nccbs, ICP_NCCBS);
194 #endif
195
196 /*
197 * Initalize the controller.
198 */
199 if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
200 printf("%s: screen service init error %d\n",
201 icp->icp_dv.dv_xname, icp->icp_status);
202 goto bail_out;
203 }
204
205 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
206 printf("%s: cache service init error %d\n",
207 icp->icp_dv.dv_xname, icp->icp_status);
208 goto bail_out;
209 }
210
211 icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
212
213 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
214 printf("%s: cache service mount error %d\n",
215 icp->icp_dv.dv_xname, icp->icp_status);
216 goto bail_out;
217 }
218
219 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
220 printf("%s: cache service post-mount init error %d\n",
221 icp->icp_dv.dv_xname, icp->icp_status);
222 goto bail_out;
223 }
224 cdev_cnt = (u_int16_t)icp->icp_info;
225
226 if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
227 printf("%s: raw service init error %d\n",
228 icp->icp_dv.dv_xname, icp->icp_status);
229 goto bail_out;
230 }
231
232 /*
233 * Set/get raw service features (scatter/gather).
234 */
235 feat = 0;
236 if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
237 0, 0))
238 if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
239 feat = icp->icp_info;
240
241 if ((feat & ICP_SCATTER_GATHER) == 0) {
242 #ifdef DIAGNOSTIC
243 printf("%s: scatter/gather not supported (raw service)\n",
244 icp->icp_dv.dv_xname);
245 #endif
246 noscsi = 1;
247 }
248
249 /*
250 * Set/get cache service features (scatter/gather).
251 */
252 feat = 0;
253 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
254 ICP_SCATTER_GATHER, 0))
255 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
256 feat = icp->icp_info;
257
258 if ((feat & ICP_SCATTER_GATHER) == 0) {
259 #ifdef DIAGNOSTIC
260 printf("%s: scatter/gather not supported (cache service)\n",
261 icp->icp_dv.dv_xname);
262 #endif
263 nocache = 1;
264 }
265
266 /*
267 * Pull some information from the board and dump.
268 */
269 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
270 ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
271 printf("%s: unable to retrive board info\n",
272 icp->icp_dv.dv_xname);
273 goto bail_out;
274 }
275 memcpy(&binfo, icp->icp_scr, sizeof(binfo));
276
277 printf("%s: model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
278 icp->icp_dv.dv_xname, binfo.bi_type_string, binfo.bi_raid_string,
279 binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
280
281 /*
282 * Determine the number of devices, and number of openings per
283 * device.
284 */
285 if (!nocache) {
286 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
287 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
288 0))
289 continue;
290
291 icp->icp_cdr[j].cd_size = icp->icp_info;
292 icp->icp_ndevs++;
293
294 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
295 0))
296 icp->icp_cdr[j].cd_type = icp->icp_info;
297 }
298 }
299
300 if (!noscsi)
301 icp->icp_ndevs += binfo.bi_chan_count;
302
303 if (icp->icp_ndevs != 0)
304 icp->icp_openings =
305 (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
306 #ifdef ICP_DEBUG
307 printf("%s: %d openings per device\n", icp->icp_dv.dv_xname,
308 icp->icp_openings);
309 #endif
310
311 /*
312 * Attach SCSI channels.
313 */
314 if (!noscsi) {
315 struct icp_ioc_version *iv;
316 struct icp_rawioc *ri;
317 struct icp_getch *gc;
318
319 iv = (struct icp_ioc_version *)icp->icp_scr;
320 iv->iv_version = htole32(ICP_IOC_NEWEST);
321 iv->iv_listents = ICP_MAXBUS;
322 iv->iv_firstchan = 0;
323 iv->iv_lastchan = ICP_MAXBUS - 1;
324 iv->iv_listoffset = htole32(sizeof(*iv));
325
326 if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
327 ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
328 sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
329 ri = (struct icp_rawioc *)(iv + 1);
330 for (j = 0; j < binfo.bi_chan_count; j++, ri++)
331 icp->icp_bus_id[j] = ri->ri_procid;
332 } else {
333 /*
334 * Fall back to the old method.
335 */
336 gc = (struct icp_getch *)icp->icp_scr;
337
338 for (i = 0; j < binfo.bi_chan_count; j++) {
339 if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
340 ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
341 ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
342 sizeof(*gc))) {
343 printf("%s: unable to get chan info",
344 icp->icp_dv.dv_xname);
345 goto bail_out;
346 }
347 icp->icp_bus_id[j] = gc->gc_scsiid;
348 }
349 }
350
351 for (j = 0; j < binfo.bi_chan_count; j++) {
352 if (icp->icp_bus_id[j] > ICP_MAXID_FC)
353 icp->icp_bus_id[j] = ICP_MAXID_FC;
354
355 icpa.icpa_unit = j + ICPA_UNIT_SCSI;
356 config_found_sm(&icp->icp_dv, &icpa, icp_print,
357 icp_submatch);
358 }
359 }
360
361 /*
362 * Attach cache devices.
363 */
364 if (!nocache) {
365 for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
366 if (icp->icp_cdr[j].cd_size == 0)
367 continue;
368
369 icpa.icpa_unit = j;
370 config_found_sm(&icp->icp_dv, &icpa, icp_print,
371 icp_submatch);
372 }
373 }
374
375 /*
376 * Start the watchdog.
377 */
378 icp_watchdog(icp);
379 return (0);
380
381 bail_out:
382 if (state > 4)
383 for (j = 0; j < i; j++)
384 bus_dmamap_destroy(icp->icp_dmat,
385 icp->icp_ccbs[j].ic_xfer_map);
386 if (state > 3)
387 free(icp->icp_ccbs, M_DEVBUF);
388 if (state > 2)
389 bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
390 if (state > 1)
391 bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
392 ICP_SCRATCH_SIZE);
393 if (state > 0)
394 bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
395 bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
396
397 return (1);
398 }
399
400 void
401 icp_watchdog(void *cookie)
402 {
403 struct icp_softc *icp;
404 int s;
405
406 icp = cookie;
407
408 s = splbio();
409 icp_intr(icp);
410 if (! SIMPLEQ_EMPTY(&icp->icp_ccb_queue))
411 icp_ccb_enqueue(icp, NULL);
412 splx(s);
413
414 callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
415 icp_watchdog, icp);
416 }
417
418 int
419 icp_print(void *aux, const char *pnp)
420 {
421 struct icp_attach_args *icpa;
422 const char *str;
423
424 icpa = (struct icp_attach_args *)aux;
425
426 if (pnp != NULL) {
427 if (icpa->icpa_unit < ICPA_UNIT_SCSI)
428 str = "block device";
429 else
430 str = "SCSI channel";
431 printf("%s at %s", str, pnp);
432 }
433 printf(" unit %d", icpa->icpa_unit);
434
435 return (UNCONF);
436 }
437
438 int
439 icp_submatch(struct device *parent, struct cfdata *cf, void *aux)
440 {
441 struct icp_attach_args *icpa;
442
443 icpa = (struct icp_attach_args *)aux;
444
445 if (cf->icpacf_unit != ICPCF_UNIT_DEFAULT &&
446 cf->icpacf_unit != icpa->icpa_unit)
447 return (0);
448
449 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
450 }
451
452 int
453 icp_async_event(struct icp_softc *icp, int val)
454 {
455
456 /* XXX */
457 return (1);
458 }
459
460 int
461 icp_intr(void *cookie)
462 {
463 struct icp_softc *icp;
464 struct icp_intr_ctx ctx;
465 struct icp_ccb *ic;
466
467 icp = cookie;
468
469 ctx.istatus = (*icp->icp_get_status)(icp);
470 if (!ctx.istatus) {
471 icp->icp_status = ICP_S_NO_STATUS;
472 return (0);
473 }
474
475 (*icp->icp_intr)(icp, &ctx);
476
477 icp->icp_status = ctx.cmd_status;
478 icp->icp_info = ctx.info;
479 icp->icp_info2 = ctx.info2;
480
481 switch (ctx.istatus) {
482 case ICP_ASYNCINDEX:
483 icp_async_event(icp, ctx.service);
484 return (1);
485
486 case ICP_SPEZINDEX:
487 printf("%s: uninitialized or unknown service (%d/%d)\n",
488 icp->icp_dv.dv_xname, ctx.info, ctx.info2);
489 return (1);
490 }
491
492 if ((ctx.istatus - 2) > icp->icp_nccbs)
493 panic("icp_intr: bad command index returned");
494
495 ic = &icp->icp_ccbs[ctx.istatus - 2];
496 ic->ic_status = icp->icp_status;
497
498 if ((ic->ic_flags & IC_ALLOCED) == 0)
499 panic("icp_intr: inactive CCB identified");
500
501 switch (icp->icp_status) {
502 case ICP_S_BSY:
503 #ifdef ICP_DEBUG
504 printf("%s: ICP_S_BSY received\n", icp->icp_dv.dv_xname);
505 #endif
506 SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
507 break;
508
509 default:
510 ic->ic_flags |= IC_COMPLETE;
511
512 if ((ic->ic_flags & IC_WAITING) != 0)
513 wakeup(ic);
514 else if (ic->ic_intr != NULL)
515 (*ic->ic_intr)(ic);
516
517 if (! SIMPLEQ_EMPTY(&icp->icp_ccb_queue))
518 icp_ccb_enqueue(icp, NULL);
519
520 break;
521 }
522
523 return (1);
524 }
525
526 int
527 icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
528 u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
529 {
530 struct icp_ioctlcmd *icmd;
531 struct icp_cachecmd *cc;
532 struct icp_rawcmd *rc;
533 int retries, rv;
534 struct icp_ccb *ic;
535
536 retries = ICP_RETRIES;
537
538 do {
539 ic = icp_ccb_alloc(icp);
540 memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
541 ic->ic_cmd.cmd_opcode = htole16(opcode);
542
543 switch (service) {
544 case ICP_CACHESERVICE:
545 if (opcode == ICP_IOCTL) {
546 icmd = &ic->ic_cmd.cmd_packet.ic;
547 icmd->ic_subfunc = htole16(arg1);
548 icmd->ic_channel = htole32(arg2);
549 icmd->ic_bufsize = htole32(arg3);
550 icmd->ic_addr =
551 htole32(icp->icp_scr_seg[0].ds_addr);
552
553 bus_dmamap_sync(icp->icp_dmat,
554 icp->icp_scr_dmamap, 0, arg3,
555 BUS_DMASYNC_PREWRITE |
556 BUS_DMASYNC_PREREAD);
557 } else {
558 cc = &ic->ic_cmd.cmd_packet.cc;
559 cc->cc_deviceno = htole16(arg1);
560 cc->cc_blockno = htole32(arg2);
561 }
562 break;
563
564 case ICP_SCSIRAWSERVICE:
565 rc = &ic->ic_cmd.cmd_packet.rc;
566 rc->rc_direction = htole32(arg1);
567 rc->rc_bus = arg2;
568 rc->rc_target = arg3;
569 rc->rc_lun = arg3 >> 8;
570 break;
571 }
572
573 ic->ic_service = service;
574 ic->ic_cmdlen = sizeof(ic->ic_cmd);
575 rv = icp_ccb_poll(icp, ic, 10000);
576
577 switch (service) {
578 case ICP_CACHESERVICE:
579 if (opcode == ICP_IOCTL) {
580 bus_dmamap_sync(icp->icp_dmat,
581 icp->icp_scr_dmamap, 0, arg3,
582 BUS_DMASYNC_POSTWRITE |
583 BUS_DMASYNC_POSTREAD);
584 }
585 break;
586 }
587
588 icp_ccb_free(icp, ic);
589 } while (rv != 0 && --retries > 0);
590
591 return (icp->icp_status == ICP_S_OK);
592 }
593
594 struct icp_ccb *
595 icp_ccb_alloc(struct icp_softc *icp)
596 {
597 struct icp_ccb *ic;
598 int s;
599
600 s = splbio();
601 ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist);
602 SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
603 splx(s);
604
605 ic->ic_flags = IC_ALLOCED;
606 return (ic);
607 }
608
609 void
610 icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
611 {
612 int s;
613
614 s = splbio();
615 ic->ic_flags = 0;
616 ic->ic_intr = NULL;
617 SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
618 splx(s);
619 }
620
621 void
622 icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
623 {
624 int s;
625
626 s = splbio();
627
628 if (ic != NULL)
629 SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
630
631 while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL) {
632 if ((*icp->icp_test_busy)(icp))
633 break;
634 icp_ccb_submit(icp, ic);
635 SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
636 }
637
638 splx(s);
639 }
640
641 int
642 icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
643 int dir)
644 {
645 struct icp_sg *sg;
646 int nsegs, i, rv;
647 bus_dmamap_t xfer;
648
649 xfer = ic->ic_xfer_map;
650
651 rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
652 BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
653 ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
654 if (rv != 0)
655 return (rv);
656
657 nsegs = xfer->dm_nsegs;
658 ic->ic_xfer_size = size;
659 ic->ic_nsgent = nsegs;
660 ic->ic_flags |= dir;
661 sg = ic->ic_sg;
662
663 if (sg != NULL) {
664 for (i = 0; i < nsegs; i++, sg++) {
665 sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
666 sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
667 }
668 } else if (nsegs > 1)
669 panic("icp_ccb_map: no SG list specified, but nsegs > 1\n");
670
671 if ((dir & IC_XFER_OUT) != 0)
672 i = BUS_DMASYNC_PREWRITE;
673 else /* if ((dir & IC_XFER_IN) != 0) */
674 i = BUS_DMASYNC_PREREAD;
675
676 bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
677 return (0);
678 }
679
680 void
681 icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
682 {
683 int i;
684
685 if ((ic->ic_flags & IC_XFER_OUT) != 0)
686 i = BUS_DMASYNC_POSTWRITE;
687 else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
688 i = BUS_DMASYNC_POSTREAD;
689
690 bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
691 bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
692 }
693
694 int
695 icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
696 {
697 int rv;
698
699 for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
700 if (!(*icp->icp_test_busy)(icp))
701 break;
702 DELAY(10);
703 }
704 if (timo == 0) {
705 printf("%s: submit: busy\n", icp->icp_dv.dv_xname);
706 return (EAGAIN);
707 }
708
709 icp_ccb_submit(icp, ic);
710
711 for (timo *= 10; timo != 0; timo--) {
712 DELAY(100);
713 icp_intr(icp);
714 if ((ic->ic_flags & IC_COMPLETE) != 0)
715 break;
716 }
717
718 if (timo != 0) {
719 if (ic->ic_status != ICP_S_OK) {
720 #ifdef ICP_DEBUG
721 printf("%s: request failed; status=0x%04x\n",
722 icp->icp_dv.dv_xname, ic->ic_status);
723 #endif
724 rv = EIO;
725 } else
726 rv = 0;
727 } else {
728 printf("%s: command timed out\n", icp->icp_dv.dv_xname);
729 rv = EIO;
730 }
731
732 while ((*icp->icp_test_busy)(icp) != 0)
733 DELAY(10);
734
735 return (rv);
736 }
737
738 int
739 icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
740 {
741 int s, rv;
742
743 ic->ic_flags |= IC_WAITING;
744
745 s = splbio();
746 icp_ccb_enqueue(icp, ic);
747 if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
748 splx(s);
749 return (rv);
750 }
751 splx(s);
752
753 if (ic->ic_status != ICP_S_OK) {
754 printf("%s: command failed; status=%x\n", icp->icp_dv.dv_xname,
755 ic->ic_status);
756 return (EIO);
757 }
758
759 return (0);
760 }
761
762 void
763 icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
764 {
765
766 ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
767
768 (*icp->icp_set_sema0)(icp);
769 DELAY(10);
770
771 ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
772 ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
773
774 (*icp->icp_copy_cmd)(icp, ic);
775 (*icp->icp_release_event)(icp, ic);
776 }
777