Annotation of src/sys/dev/ic/icp.c, Revision 1.27.2.1
1.27.2.1! yamt 1: /* $NetBSD: icp.c,v 1.27 2008/04/08 12:07:26 cegger Exp $ */
1.1 ad 2:
3: /*-
1.8 thorpej 4: * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
1.1 ad 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.8 thorpej 8: * by Andrew Doran, and by Jason R. Thorpe of Wasabi Systems, Inc.
1.1 ad 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: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
34: *
35: * Redistribution and use in source and binary forms, with or without
36: * modification, are permitted provided that the following conditions
37: * are met:
38: * 1. Redistributions of source code must retain the above copyright
39: * notice, this list of conditions and the following disclaimer.
40: * 2. Redistributions in binary form must reproduce the above copyright
41: * notice, this list of conditions and the following disclaimer in the
42: * documentation and/or other materials provided with the distribution.
43: * 3. All advertising materials mentioning features or use of this software
44: * must display the following acknowledgement:
45: * This product includes software developed by Niklas Hallqvist.
46: * 4. The name of the author may not be used to endorse or promote products
47: * derived from this software without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
50: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
51: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
52: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
53: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
54: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
55: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
56: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
58: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59: *
60: * from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
61: */
62:
63: /*
64: * This driver would not have written if it was not for the hardware donations
65: * from both ICP-Vortex and Öko.neT. I want to thank them for their support.
66: *
67: * Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by
68: * Intel.
1.8 thorpej 69: *
70: * Support for the ICP-Vortex management tools added by
71: * Jason R. Thorpe of Wasabi Systems, Inc., based on code
1.10 thorpej 72: * provided by Achim Leubner <achim.leubner@intel.com>.
73: *
74: * Additional support for dynamic rescan of cacheservice drives by
75: * Jason R. Thorpe of Wasabi Systems, Inc.
1.1 ad 76: */
77:
78: #include <sys/cdefs.h>
1.27.2.1! yamt 79: __KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.27 2008/04/08 12:07:26 cegger Exp $");
1.1 ad 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:
1.18 dsl 94: #include <sys/bswap.h>
1.26 ad 95: #include <sys/bus.h>
1.1 ad 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:
1.8 thorpej 104: #include <dev/scsipi/scsipi_all.h>
105: #include <dev/scsipi/scsiconf.h>
106:
1.13 drochner 107: #include "locators.h"
108:
1.1 ad 109: int icp_async_event(struct icp_softc *, int);
110: void icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
111: void icp_chain(struct icp_softc *);
112: int icp_print(void *, const char *);
113: void icp_watchdog(void *);
1.8 thorpej 114: void icp_ucmd_intr(struct icp_ccb *);
1.10 thorpej 115: void icp_recompute_openings(struct icp_softc *);
1.8 thorpej 116:
117: int icp_count; /* total # of controllers, for ioctl interface */
118:
119: /*
120: * Statistics for the ioctl interface to query.
121: *
122: * XXX Global. They should probably be made per-controller
123: * XXX at some point.
124: */
125: gdt_statist_t icp_stats;
1.1 ad 126:
127: int
128: icp_init(struct icp_softc *icp, const char *intrstr)
129: {
130: struct icp_attach_args icpa;
131: struct icp_binfo binfo;
132: struct icp_ccb *ic;
133: u_int16_t cdev_cnt;
1.12 mycroft 134: int i, j, state, feat, nsegs, rv;
1.15 drochner 135: int locs[ICPCF_NLOCS];
1.1 ad 136:
1.5 simonb 137: state = 0;
1.1 ad 138:
139: if (intrstr != NULL)
1.27 cegger 140: aprint_normal_dev(&icp->icp_dv, "interrupting at %s\n",
1.1 ad 141: intrstr);
142:
143: SIMPLEQ_INIT(&icp->icp_ccb_queue);
144: SIMPLEQ_INIT(&icp->icp_ccb_freelist);
1.8 thorpej 145: SIMPLEQ_INIT(&icp->icp_ucmd_queue);
1.25 ad 146: callout_init(&icp->icp_wdog_callout, 0);
1.1 ad 147:
148: /*
149: * Allocate a scratch area.
150: */
151: if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
152: ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
153: &icp->icp_scr_dmamap) != 0) {
1.27 cegger 154: aprint_error_dev(&icp->icp_dv, "cannot create scratch dmamap\n");
1.1 ad 155: return (1);
156: }
157: state++;
158:
159: if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
160: icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
1.27 cegger 161: aprint_error_dev(&icp->icp_dv, "cannot alloc scratch dmamem\n");
1.1 ad 162: goto bail_out;
163: }
164: state++;
165:
166: if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
167: ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
1.27 cegger 168: aprint_error_dev(&icp->icp_dv, "cannot map scratch dmamem\n");
1.1 ad 169: goto bail_out;
170: }
171: state++;
172:
173: if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
174: ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
1.27 cegger 175: aprint_error_dev(&icp->icp_dv, "cannot load scratch dmamap\n");
1.1 ad 176: goto bail_out;
177: }
178: state++;
179:
180: /*
181: * Allocate and initialize the command control blocks.
182: */
183: ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
184: if ((icp->icp_ccbs = ic) == NULL) {
1.27 cegger 185: aprint_error_dev(&icp->icp_dv, "malloc() failed\n");
1.1 ad 186: goto bail_out;
187: }
188: state++;
189:
190: for (i = 0; i < ICP_NCCBS; i++, ic++) {
191: /*
192: * The first two command indexes have special meanings, so
193: * we can't use them.
194: */
195: ic->ic_ident = i + 2;
196: rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
197: ICP_MAXSG, ICP_MAX_XFER, 0,
198: BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
199: &ic->ic_xfer_map);
200: if (rv != 0)
201: break;
202: icp->icp_nccbs++;
203: icp_ccb_free(icp, ic);
204: }
205: #ifdef DIAGNOSTIC
206: if (icp->icp_nccbs != ICP_NCCBS)
1.27 cegger 207: aprint_error_dev(&icp->icp_dv, "%d/%d CCBs usable\n",
1.1 ad 208: icp->icp_nccbs, ICP_NCCBS);
209: #endif
210:
211: /*
212: * Initalize the controller.
213: */
214: if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
1.27 cegger 215: aprint_error_dev(&icp->icp_dv, "screen service init error %d\n",
216: icp->icp_status);
1.1 ad 217: goto bail_out;
218: }
219:
220: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
1.27 cegger 221: aprint_error_dev(&icp->icp_dv, "cache service init error %d\n",
222: icp->icp_status);
1.1 ad 223: goto bail_out;
224: }
225:
226: icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
227:
228: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
1.27 cegger 229: aprint_error_dev(&icp->icp_dv, "cache service mount error %d\n",
230: icp->icp_status);
1.1 ad 231: goto bail_out;
232: }
233:
234: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
1.27 cegger 235: aprint_error_dev(&icp->icp_dv, "cache service post-mount init error %d\n",
236: icp->icp_status);
1.1 ad 237: goto bail_out;
238: }
239: cdev_cnt = (u_int16_t)icp->icp_info;
1.8 thorpej 240: icp->icp_fw_vers = icp->icp_service;
1.1 ad 241:
242: if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
1.27 cegger 243: aprint_error_dev(&icp->icp_dv, "raw service init error %d\n",
244: icp->icp_status);
1.1 ad 245: goto bail_out;
246: }
247:
248: /*
249: * Set/get raw service features (scatter/gather).
250: */
251: feat = 0;
252: if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
253: 0, 0))
254: if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
255: feat = icp->icp_info;
256:
257: if ((feat & ICP_SCATTER_GATHER) == 0) {
258: #ifdef DIAGNOSTIC
1.27 cegger 259: aprint_normal_dev(&icp->icp_dv,
260: "scatter/gather not supported (raw service)\n");
1.1 ad 261: #endif
1.10 thorpej 262: } else
263: icp->icp_features |= ICP_FEAT_RAWSERVICE;
1.1 ad 264:
265: /*
266: * Set/get cache service features (scatter/gather).
267: */
268: feat = 0;
269: if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
270: ICP_SCATTER_GATHER, 0))
271: if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
272: feat = icp->icp_info;
273:
274: if ((feat & ICP_SCATTER_GATHER) == 0) {
275: #ifdef DIAGNOSTIC
1.27 cegger 276: aprint_normal_dev(&icp->icp_dv,
277: "scatter/gather not supported (cache service)\n");
1.1 ad 278: #endif
1.10 thorpej 279: } else
280: icp->icp_features |= ICP_FEAT_CACHESERVICE;
1.1 ad 281:
282: /*
283: * Pull some information from the board and dump.
284: */
285: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
286: ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
1.27 cegger 287: aprint_error_dev(&icp->icp_dv, "unable to retrive board info\n");
1.1 ad 288: goto bail_out;
289: }
290: memcpy(&binfo, icp->icp_scr, sizeof(binfo));
291:
1.27 cegger 292: aprint_normal_dev(&icp->icp_dv,
293: "model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
294: binfo.bi_type_string, binfo.bi_raid_string,
1.1 ad 295: binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
296:
297: /*
298: * Determine the number of devices, and number of openings per
299: * device.
300: */
1.10 thorpej 301: if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
1.1 ad 302: for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
303: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
304: 0))
305: continue;
306:
307: icp->icp_cdr[j].cd_size = icp->icp_info;
1.10 thorpej 308: if (icp->icp_cdr[j].cd_size != 0)
309: icp->icp_ndevs++;
1.1 ad 310:
311: if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
312: 0))
313: icp->icp_cdr[j].cd_type = icp->icp_info;
314: }
315: }
316:
1.10 thorpej 317: if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
318: icp->icp_nchan = binfo.bi_chan_count;
319: icp->icp_ndevs += icp->icp_nchan;
320: }
1.1 ad 321:
1.10 thorpej 322: icp_recompute_openings(icp);
1.1 ad 323:
324: /*
325: * Attach SCSI channels.
326: */
1.10 thorpej 327: if (icp->icp_features & ICP_FEAT_RAWSERVICE) {
1.1 ad 328: struct icp_ioc_version *iv;
329: struct icp_rawioc *ri;
330: struct icp_getch *gc;
331:
332: iv = (struct icp_ioc_version *)icp->icp_scr;
333: iv->iv_version = htole32(ICP_IOC_NEWEST);
334: iv->iv_listents = ICP_MAXBUS;
335: iv->iv_firstchan = 0;
336: iv->iv_lastchan = ICP_MAXBUS - 1;
337: iv->iv_listoffset = htole32(sizeof(*iv));
338:
339: if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
340: ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
341: sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
342: ri = (struct icp_rawioc *)(iv + 1);
343: for (j = 0; j < binfo.bi_chan_count; j++, ri++)
344: icp->icp_bus_id[j] = ri->ri_procid;
345: } else {
346: /*
347: * Fall back to the old method.
348: */
349: gc = (struct icp_getch *)icp->icp_scr;
350:
1.12 mycroft 351: for (j = 0; j < binfo.bi_chan_count; j++) {
1.1 ad 352: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
353: ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
354: ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
355: sizeof(*gc))) {
1.27 cegger 356: aprint_error_dev(&icp->icp_dv,
357: "unable to get chan info");
1.1 ad 358: goto bail_out;
359: }
360: icp->icp_bus_id[j] = gc->gc_scsiid;
361: }
362: }
363:
364: for (j = 0; j < binfo.bi_chan_count; j++) {
365: if (icp->icp_bus_id[j] > ICP_MAXID_FC)
366: icp->icp_bus_id[j] = ICP_MAXID_FC;
367:
368: icpa.icpa_unit = j + ICPA_UNIT_SCSI;
1.13 drochner 369:
1.15 drochner 370: locs[ICPCF_UNIT] = j + ICPA_UNIT_SCSI;
1.13 drochner 371:
1.10 thorpej 372: icp->icp_children[icpa.icpa_unit] =
1.15 drochner 373: config_found_sm_loc(&icp->icp_dv, "icp", locs,
1.16 drochner 374: &icpa, icp_print, config_stdsubmatch);
1.1 ad 375: }
376: }
377:
378: /*
379: * Attach cache devices.
380: */
1.10 thorpej 381: if (icp->icp_features & ICP_FEAT_CACHESERVICE) {
1.1 ad 382: for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
383: if (icp->icp_cdr[j].cd_size == 0)
384: continue;
1.14 perry 385:
1.1 ad 386: icpa.icpa_unit = j;
1.13 drochner 387:
1.15 drochner 388: locs[ICPCF_UNIT] = j;
1.13 drochner 389:
1.10 thorpej 390: icp->icp_children[icpa.icpa_unit] =
1.15 drochner 391: config_found_sm_loc(&icp->icp_dv, "icp", locs,
1.16 drochner 392: &icpa, icp_print, config_stdsubmatch);
1.1 ad 393: }
394: }
395:
396: /*
397: * Start the watchdog.
398: */
399: icp_watchdog(icp);
1.8 thorpej 400:
401: /*
402: * Count the controller, and we're done!
403: */
1.24 ad 404: if (icp_count++ == 0)
405: mutex_init(&icp_ioctl_mutex, MUTEX_DEFAULT, IPL_NONE);
1.8 thorpej 406:
1.1 ad 407: return (0);
408:
409: bail_out:
410: if (state > 4)
411: for (j = 0; j < i; j++)
412: bus_dmamap_destroy(icp->icp_dmat,
413: icp->icp_ccbs[j].ic_xfer_map);
414: if (state > 3)
415: free(icp->icp_ccbs, M_DEVBUF);
416: if (state > 2)
417: bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
418: if (state > 1)
419: bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
420: ICP_SCRATCH_SIZE);
421: if (state > 0)
422: bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
423: bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
424:
425: return (1);
426: }
427:
428: void
1.10 thorpej 429: icp_register_servicecb(struct icp_softc *icp, int unit,
430: const struct icp_servicecb *cb)
431: {
432:
433: icp->icp_servicecb[unit] = cb;
434: }
435:
436: void
437: icp_rescan(struct icp_softc *icp, int unit)
438: {
439: struct icp_attach_args icpa;
440: u_int newsize, newtype;
1.15 drochner 441: int locs[ICPCF_NLOCS];
1.10 thorpej 442:
443: /*
444: * NOTE: It is very important that the queue be frozen and not
445: * commands running when this is called. The ioctl mutex must
446: * also be held.
447: */
448:
449: KASSERT(icp->icp_qfreeze != 0);
450: KASSERT(icp->icp_running == 0);
451: KASSERT(unit < ICP_MAX_HDRIVES);
452:
453: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, unit, 0, 0)) {
454: #ifdef ICP_DEBUG
455: printf("%s: rescan: unit %d ICP_INFO failed -> 0x%04x\n",
1.27 cegger 456: device_xname(&icp->icp_dv), unit, icp->icp_status);
1.10 thorpej 457: #endif
458: goto gone;
459: }
460: if ((newsize = icp->icp_info) == 0) {
461: #ifdef ICP_DEBUG
462: printf("%s: rescan: unit %d has zero size\n",
1.27.2.1! yamt 463: device_xname(&icp->icp_dv), unit);
1.10 thorpej 464: #endif
465: gone:
466: /*
467: * Host drive is no longer present; detach if a child
468: * is currently there.
469: */
470: if (icp->icp_cdr[unit].cd_size != 0)
471: icp->icp_ndevs--;
472: icp->icp_cdr[unit].cd_size = 0;
473: if (icp->icp_children[unit] != NULL) {
474: (void) config_detach(icp->icp_children[unit],
475: DETACH_FORCE);
476: icp->icp_children[unit] = NULL;
477: }
478: return;
479: }
480:
481: if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, unit, 0, 0))
482: newtype = icp->icp_info;
483: else {
484: #ifdef ICP_DEBUG
485: printf("%s: rescan: unit %d ICP_DEVTYPE failed\n",
1.27 cegger 486: device_xname(&icp->icp_dv), unit);
1.10 thorpej 487: #endif
488: newtype = 0; /* XXX? */
489: }
490:
491: #ifdef ICP_DEBUG
492: printf("%s: rescan: unit %d old %u/%u, new %u/%u\n",
1.27 cegger 493: device_xname(&icp->icp_dv), unit, icp->icp_cdr[unit].cd_size,
1.10 thorpej 494: icp->icp_cdr[unit].cd_type, newsize, newtype);
495: #endif
496:
497: /*
498: * If the type or size changed, detach any old child (if it exists)
499: * and attach a new one.
500: */
501: if (icp->icp_children[unit] == NULL ||
502: newsize != icp->icp_cdr[unit].cd_size ||
503: newtype != icp->icp_cdr[unit].cd_type) {
504: if (icp->icp_cdr[unit].cd_size == 0)
505: icp->icp_ndevs++;
506: icp->icp_cdr[unit].cd_size = newsize;
507: icp->icp_cdr[unit].cd_type = newtype;
508: if (icp->icp_children[unit] != NULL)
509: (void) config_detach(icp->icp_children[unit],
510: DETACH_FORCE);
511:
512: icpa.icpa_unit = unit;
1.13 drochner 513:
1.15 drochner 514: locs[ICPCF_UNIT] = unit;
1.13 drochner 515:
516: icp->icp_children[unit] = config_found_sm_loc(&icp->icp_dv,
1.16 drochner 517: "icp", locs, &icpa, icp_print, config_stdsubmatch);
1.10 thorpej 518: }
519:
520: icp_recompute_openings(icp);
521: }
522:
523: void
524: icp_rescan_all(struct icp_softc *icp)
525: {
526: int unit;
527: u_int16_t cdev_cnt;
528:
529: /*
530: * This is the old method of rescanning the host drives. We
531: * start by reinitializing the cache service.
532: */
533: if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
534: printf("%s: unable to re-initialize cache service for rescan\n",
1.27 cegger 535: device_xname(&icp->icp_dv));
1.10 thorpej 536: return;
537: }
538: cdev_cnt = (u_int16_t) icp->icp_info;
539:
540: /* For each host drive, do the new-style rescan. */
541: for (unit = 0; unit < cdev_cnt && unit < ICP_MAX_HDRIVES; unit++)
542: icp_rescan(icp, unit);
543:
544: /* Now detach anything in the slots after cdev_cnt. */
545: for (; unit < ICP_MAX_HDRIVES; unit++) {
546: if (icp->icp_cdr[unit].cd_size != 0) {
547: #ifdef ICP_DEBUG
548: printf("%s: rescan all: unit %d < new cdev_cnt (%d)\n",
1.27 cegger 549: device_xname(&icp->icp_dv), unit, cdev_cnt);
1.10 thorpej 550: #endif
551: icp->icp_ndevs--;
552: icp->icp_cdr[unit].cd_size = 0;
553: if (icp->icp_children[unit] != NULL) {
554: (void) config_detach(icp->icp_children[unit],
555: DETACH_FORCE);
556: icp->icp_children[unit] = NULL;
557: }
558: }
559: }
560:
561: icp_recompute_openings(icp);
562: }
563:
564: void
565: icp_recompute_openings(struct icp_softc *icp)
566: {
567: int unit, openings;
568:
569: if (icp->icp_ndevs != 0)
570: openings =
571: (icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
572: else
573: openings = 0;
574: if (openings == icp->icp_openings)
575: return;
576: icp->icp_openings = openings;
577:
578: #ifdef ICP_DEBUG
579: printf("%s: %d device%s, %d openings per device\n",
1.27 cegger 580: device_xname(&icp->icp_dv), icp->icp_ndevs,
1.10 thorpej 581: icp->icp_ndevs == 1 ? "" : "s", icp->icp_openings);
582: #endif
583:
584: for (unit = 0; unit < ICP_MAX_HDRIVES + ICP_MAXBUS; unit++) {
585: if (icp->icp_children[unit] != NULL)
586: (*icp->icp_servicecb[unit]->iscb_openings)(
587: icp->icp_children[unit], icp->icp_openings);
588: }
589: }
590:
591: void
1.1 ad 592: icp_watchdog(void *cookie)
593: {
594: struct icp_softc *icp;
595: int s;
596:
597: icp = cookie;
598:
599: s = splbio();
600: icp_intr(icp);
1.8 thorpej 601: if (ICP_HAS_WORK(icp))
1.1 ad 602: icp_ccb_enqueue(icp, NULL);
603: splx(s);
604:
605: callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
606: icp_watchdog, icp);
607: }
608:
609: int
610: icp_print(void *aux, const char *pnp)
611: {
612: struct icp_attach_args *icpa;
613: const char *str;
614:
615: icpa = (struct icp_attach_args *)aux;
616:
617: if (pnp != NULL) {
618: if (icpa->icpa_unit < ICPA_UNIT_SCSI)
619: str = "block device";
620: else
621: str = "SCSI channel";
1.6 thorpej 622: aprint_normal("%s at %s", str, pnp);
1.1 ad 623: }
1.6 thorpej 624: aprint_normal(" unit %d", icpa->icpa_unit);
1.1 ad 625:
626: return (UNCONF);
627: }
628:
629: int
1.8 thorpej 630: icp_async_event(struct icp_softc *icp, int service)
1.1 ad 631: {
632:
1.8 thorpej 633: if (service == ICP_SCREENSERVICE) {
634: if (icp->icp_status == ICP_S_MSG_REQUEST) {
635: /* XXX */
636: }
637: } else {
638: if ((icp->icp_fw_vers & 0xff) >= 0x1a) {
639: icp->icp_evt.size = 0;
1.19 thorpej 640: icp->icp_evt.eu.async.ionode =
641: device_unit(&icp->icp_dv);
1.8 thorpej 642: icp->icp_evt.eu.async.status = icp->icp_status;
643: /*
644: * Severity and event string are filled in by the
645: * hardware interface interrupt handler.
646: */
1.27 cegger 647: printf("%s: %s\n", device_xname(&icp->icp_dv),
1.8 thorpej 648: icp->icp_evt.event_string);
649: } else {
650: icp->icp_evt.size = sizeof(icp->icp_evt.eu.async);
1.19 thorpej 651: icp->icp_evt.eu.async.ionode =
652: device_unit(&icp->icp_dv);
1.8 thorpej 653: icp->icp_evt.eu.async.service = service;
654: icp->icp_evt.eu.async.status = icp->icp_status;
655: icp->icp_evt.eu.async.info = icp->icp_info;
656: /* XXXJRT FIX THIS */
1.14 perry 657: *(u_int32_t *) icp->icp_evt.eu.async.scsi_coord =
1.8 thorpej 658: icp->icp_info2;
659: }
660: icp_store_event(icp, GDT_ES_ASYNC, service, &icp->icp_evt);
661: }
662:
663: return (0);
1.1 ad 664: }
665:
666: int
667: icp_intr(void *cookie)
668: {
669: struct icp_softc *icp;
670: struct icp_intr_ctx ctx;
671: struct icp_ccb *ic;
672:
673: icp = cookie;
674:
675: ctx.istatus = (*icp->icp_get_status)(icp);
676: if (!ctx.istatus) {
677: icp->icp_status = ICP_S_NO_STATUS;
678: return (0);
679: }
680:
681: (*icp->icp_intr)(icp, &ctx);
682:
683: icp->icp_status = ctx.cmd_status;
1.8 thorpej 684: icp->icp_service = ctx.service;
1.1 ad 685: icp->icp_info = ctx.info;
686: icp->icp_info2 = ctx.info2;
687:
688: switch (ctx.istatus) {
689: case ICP_ASYNCINDEX:
690: icp_async_event(icp, ctx.service);
691: return (1);
692:
693: case ICP_SPEZINDEX:
1.27 cegger 694: aprint_error_dev(&icp->icp_dv, "uninitialized or unknown service (%d/%d)\n",
695: ctx.info, ctx.info2);
1.8 thorpej 696: icp->icp_evt.size = sizeof(icp->icp_evt.eu.driver);
1.19 thorpej 697: icp->icp_evt.eu.driver.ionode = device_unit(&icp->icp_dv);
1.8 thorpej 698: icp_store_event(icp, GDT_ES_DRIVER, 4, &icp->icp_evt);
1.1 ad 699: return (1);
700: }
701:
702: if ((ctx.istatus - 2) > icp->icp_nccbs)
703: panic("icp_intr: bad command index returned");
704:
705: ic = &icp->icp_ccbs[ctx.istatus - 2];
706: ic->ic_status = icp->icp_status;
707:
1.8 thorpej 708: if ((ic->ic_flags & IC_ALLOCED) == 0) {
709: /* XXX ICP's "iir" driver just sends an event here. */
1.1 ad 710: panic("icp_intr: inactive CCB identified");
1.8 thorpej 711: }
1.1 ad 712:
1.10 thorpej 713: /*
714: * Try to protect ourselves from the running command count already
715: * being 0 (e.g. if a polled command times out).
716: */
717: KDASSERT(icp->icp_running != 0);
718: if (--icp->icp_running == 0 &&
719: (icp->icp_flags & ICP_F_WAIT_FREEZE) != 0) {
720: icp->icp_flags &= ~ICP_F_WAIT_FREEZE;
721: wakeup(&icp->icp_qfreeze);
722: }
723:
1.1 ad 724: switch (icp->icp_status) {
725: case ICP_S_BSY:
726: #ifdef ICP_DEBUG
1.27 cegger 727: printf("%s: ICP_S_BSY received\n", device_xname(&icp->icp_dv));
1.1 ad 728: #endif
1.8 thorpej 729: if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
730: SIMPLEQ_INSERT_HEAD(&icp->icp_ucmd_queue, ic, ic_chain);
731: else
732: SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
1.1 ad 733: break;
734:
735: default:
736: ic->ic_flags |= IC_COMPLETE;
737:
738: if ((ic->ic_flags & IC_WAITING) != 0)
739: wakeup(ic);
740: else if (ic->ic_intr != NULL)
741: (*ic->ic_intr)(ic);
742:
1.8 thorpej 743: if (ICP_HAS_WORK(icp))
1.1 ad 744: icp_ccb_enqueue(icp, NULL);
745:
746: break;
747: }
748:
749: return (1);
750: }
751:
1.8 thorpej 752: struct icp_ucmd_ctx {
753: gdt_ucmd_t *iu_ucmd;
754: u_int32_t iu_cnt;
755: };
756:
757: void
758: icp_ucmd_intr(struct icp_ccb *ic)
759: {
760: struct icp_softc *icp = (void *) ic->ic_dv;
761: struct icp_ucmd_ctx *iu = ic->ic_context;
762: gdt_ucmd_t *ucmd = iu->iu_ucmd;
763:
764: ucmd->status = icp->icp_status;
765: ucmd->info = icp->icp_info;
766:
767: if (iu->iu_cnt != 0) {
768: bus_dmamap_sync(icp->icp_dmat,
769: icp->icp_scr_dmamap,
770: ICP_SCRATCH_UCMD, iu->iu_cnt,
771: BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
772: memcpy(ucmd->data,
1.23 christos 773: (char *)icp->icp_scr + ICP_SCRATCH_UCMD, iu->iu_cnt);
1.8 thorpej 774: }
775:
776: icp->icp_ucmd_ccb = NULL;
777:
778: ic->ic_flags |= IC_COMPLETE;
779: wakeup(ic);
780: }
781:
782: /*
783: * NOTE: We assume that it is safe to sleep here!
784: */
1.1 ad 785: int
786: icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
787: u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
788: {
789: struct icp_ioctlcmd *icmd;
790: struct icp_cachecmd *cc;
791: struct icp_rawcmd *rc;
792: int retries, rv;
793: struct icp_ccb *ic;
794:
795: retries = ICP_RETRIES;
796:
797: do {
1.8 thorpej 798: ic = icp_ccb_alloc_wait(icp);
1.1 ad 799: memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
800: ic->ic_cmd.cmd_opcode = htole16(opcode);
801:
802: switch (service) {
803: case ICP_CACHESERVICE:
804: if (opcode == ICP_IOCTL) {
805: icmd = &ic->ic_cmd.cmd_packet.ic;
806: icmd->ic_subfunc = htole16(arg1);
807: icmd->ic_channel = htole32(arg2);
808: icmd->ic_bufsize = htole32(arg3);
809: icmd->ic_addr =
810: htole32(icp->icp_scr_seg[0].ds_addr);
811:
812: bus_dmamap_sync(icp->icp_dmat,
813: icp->icp_scr_dmamap, 0, arg3,
814: BUS_DMASYNC_PREWRITE |
815: BUS_DMASYNC_PREREAD);
816: } else {
817: cc = &ic->ic_cmd.cmd_packet.cc;
818: cc->cc_deviceno = htole16(arg1);
819: cc->cc_blockno = htole32(arg2);
820: }
821: break;
822:
823: case ICP_SCSIRAWSERVICE:
824: rc = &ic->ic_cmd.cmd_packet.rc;
825: rc->rc_direction = htole32(arg1);
826: rc->rc_bus = arg2;
827: rc->rc_target = arg3;
828: rc->rc_lun = arg3 >> 8;
829: break;
830: }
831:
832: ic->ic_service = service;
833: ic->ic_cmdlen = sizeof(ic->ic_cmd);
834: rv = icp_ccb_poll(icp, ic, 10000);
835:
836: switch (service) {
837: case ICP_CACHESERVICE:
838: if (opcode == ICP_IOCTL) {
839: bus_dmamap_sync(icp->icp_dmat,
840: icp->icp_scr_dmamap, 0, arg3,
841: BUS_DMASYNC_POSTWRITE |
842: BUS_DMASYNC_POSTREAD);
843: }
844: break;
845: }
846:
847: icp_ccb_free(icp, ic);
848: } while (rv != 0 && --retries > 0);
849:
850: return (icp->icp_status == ICP_S_OK);
851: }
852:
1.8 thorpej 853: int
854: icp_ucmd(struct icp_softc *icp, gdt_ucmd_t *ucmd)
855: {
856: struct icp_ccb *ic;
857: struct icp_ucmd_ctx iu;
858: u_int32_t cnt;
859: int error;
860:
861: if (ucmd->service == ICP_CACHESERVICE) {
862: if (ucmd->command.cmd_opcode == ICP_IOCTL) {
863: cnt = ucmd->command.cmd_packet.ic.ic_bufsize;
864: if (cnt > GDT_SCRATCH_SZ) {
1.27 cegger 865: aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
866: GDT_SCRATCH_SZ, cnt);
1.8 thorpej 867: return (EINVAL);
868: }
869: } else {
870: cnt = ucmd->command.cmd_packet.cc.cc_blockcnt *
871: ICP_SECTOR_SIZE;
872: if (cnt > GDT_SCRATCH_SZ) {
1.27 cegger 873: aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
874: GDT_SCRATCH_SZ, cnt);
1.8 thorpej 875: return (EINVAL);
876: }
877: }
878: } else {
879: cnt = ucmd->command.cmd_packet.rc.rc_sdlen +
880: ucmd->command.cmd_packet.rc.rc_sense_len;
881: if (cnt > GDT_SCRATCH_SZ) {
1.27 cegger 882: aprint_error_dev(&icp->icp_dv, "scratch buffer too small (%d/%d)\n",
883: GDT_SCRATCH_SZ, cnt);
1.8 thorpej 884: return (EINVAL);
885: }
886: }
887:
888: iu.iu_ucmd = ucmd;
889: iu.iu_cnt = cnt;
890:
891: ic = icp_ccb_alloc_wait(icp);
892: memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
893: ic->ic_cmd.cmd_opcode = htole16(ucmd->command.cmd_opcode);
894:
895: if (ucmd->service == ICP_CACHESERVICE) {
896: if (ucmd->command.cmd_opcode == ICP_IOCTL) {
897: struct icp_ioctlcmd *icmd, *uicmd;
898:
899: icmd = &ic->ic_cmd.cmd_packet.ic;
900: uicmd = &ucmd->command.cmd_packet.ic;
901:
902: icmd->ic_subfunc = htole16(uicmd->ic_subfunc);
903: icmd->ic_channel = htole32(uicmd->ic_channel);
904: icmd->ic_bufsize = htole32(uicmd->ic_bufsize);
905: icmd->ic_addr =
906: htole32(icp->icp_scr_seg[0].ds_addr +
907: ICP_SCRATCH_UCMD);
908: } else {
909: struct icp_cachecmd *cc, *ucc;
910:
911: cc = &ic->ic_cmd.cmd_packet.cc;
912: ucc = &ucmd->command.cmd_packet.cc;
913:
914: cc->cc_deviceno = htole16(ucc->cc_deviceno);
915: cc->cc_blockno = htole32(ucc->cc_blockno);
916: cc->cc_blockcnt = htole32(ucc->cc_blockcnt);
917: cc->cc_addr = htole32(0xffffffffU);
918: cc->cc_nsgent = htole32(1);
919: cc->cc_sg[0].sg_addr =
920: htole32(icp->icp_scr_seg[0].ds_addr +
921: ICP_SCRATCH_UCMD);
922: cc->cc_sg[0].sg_len = htole32(cnt);
923: }
924: } else {
925: struct icp_rawcmd *rc, *urc;
926:
927: rc = &ic->ic_cmd.cmd_packet.rc;
928: urc = &ucmd->command.cmd_packet.rc;
929:
930: rc->rc_direction = htole32(urc->rc_direction);
931: rc->rc_sdata = htole32(0xffffffffU);
932: rc->rc_sdlen = htole32(urc->rc_sdlen);
933: rc->rc_clen = htole32(urc->rc_clen);
934: memcpy(rc->rc_cdb, urc->rc_cdb, sizeof(rc->rc_cdb));
935: rc->rc_target = urc->rc_target;
936: rc->rc_lun = urc->rc_lun;
937: rc->rc_bus = urc->rc_bus;
938: rc->rc_sense_len = htole32(urc->rc_sense_len);
939: rc->rc_sense_addr =
940: htole32(icp->icp_scr_seg[0].ds_addr +
941: ICP_SCRATCH_UCMD + urc->rc_sdlen);
942: rc->rc_nsgent = htole32(1);
943: rc->rc_sg[0].sg_addr =
944: htole32(icp->icp_scr_seg[0].ds_addr + ICP_SCRATCH_UCMD);
945: rc->rc_sg[0].sg_len = htole32(cnt - urc->rc_sense_len);
946: }
947:
948: ic->ic_service = ucmd->service;
949: ic->ic_cmdlen = sizeof(ic->ic_cmd);
950: ic->ic_context = &iu;
951:
952: /*
953: * XXX What units are ucmd->timeout in? Until we know, we
954: * XXX just pull a number out of thin air.
955: */
956: if (__predict_false((error = icp_ccb_wait_user(icp, ic, 30000)) != 0))
1.27 cegger 957: aprint_error_dev(&icp->icp_dv, "error %d waiting for ucmd to complete\n",
958: error);
1.8 thorpej 959:
960: /* icp_ucmd_intr() has updated ucmd. */
961: icp_ccb_free(icp, ic);
962:
963: return (error);
964: }
965:
1.1 ad 966: struct icp_ccb *
967: icp_ccb_alloc(struct icp_softc *icp)
968: {
969: struct icp_ccb *ic;
970: int s;
971:
972: s = splbio();
1.8 thorpej 973: if (__predict_false((ic =
974: SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL)) {
975: splx(s);
976: return (NULL);
977: }
978: SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
979: splx(s);
980:
981: ic->ic_flags = IC_ALLOCED;
982: return (ic);
983: }
984:
985: struct icp_ccb *
986: icp_ccb_alloc_wait(struct icp_softc *icp)
987: {
988: struct icp_ccb *ic;
989: int s;
990:
991: s = splbio();
992: while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist)) == NULL) {
993: icp->icp_flags |= ICP_F_WAIT_CCB;
994: (void) tsleep(&icp->icp_ccb_freelist, PRIBIO, "icpccb", 0);
995: }
1.2 lukem 996: SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic_chain);
1.1 ad 997: splx(s);
998:
999: ic->ic_flags = IC_ALLOCED;
1000: return (ic);
1001: }
1002:
1003: void
1004: icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
1005: {
1006: int s;
1007:
1008: s = splbio();
1009: ic->ic_flags = 0;
1010: ic->ic_intr = NULL;
1011: SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
1.8 thorpej 1012: if (__predict_false((icp->icp_flags & ICP_F_WAIT_CCB) != 0)) {
1013: icp->icp_flags &= ~ICP_F_WAIT_CCB;
1014: wakeup(&icp->icp_ccb_freelist);
1015: }
1.1 ad 1016: splx(s);
1017: }
1018:
1019: void
1020: icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
1021: {
1022: int s;
1023:
1024: s = splbio();
1025:
1.8 thorpej 1026: if (ic != NULL) {
1027: if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
1028: SIMPLEQ_INSERT_TAIL(&icp->icp_ucmd_queue, ic, ic_chain);
1029: else
1030: SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
1031: }
1032:
1.10 thorpej 1033: for (; icp->icp_qfreeze == 0;) {
1.8 thorpej 1034: if (__predict_false((ic =
1035: SIMPLEQ_FIRST(&icp->icp_ucmd_queue)) != NULL)) {
1036: struct icp_ucmd_ctx *iu = ic->ic_context;
1037: gdt_ucmd_t *ucmd = iu->iu_ucmd;
1.1 ad 1038:
1.8 thorpej 1039: /*
1040: * All user-generated commands share the same
1041: * scratch space, so if one is already running,
1042: * we have to stall the command queue.
1043: */
1044: if (icp->icp_ucmd_ccb != NULL)
1045: break;
1.9 thorpej 1046: if ((*icp->icp_test_busy)(icp))
1047: break;
1.8 thorpej 1048: icp->icp_ucmd_ccb = ic;
1049:
1050: if (iu->iu_cnt != 0) {
1.23 christos 1051: memcpy((char *)icp->icp_scr + ICP_SCRATCH_UCMD,
1.8 thorpej 1052: ucmd->data, iu->iu_cnt);
1053: bus_dmamap_sync(icp->icp_dmat,
1054: icp->icp_scr_dmamap,
1055: ICP_SCRATCH_UCMD, iu->iu_cnt,
1056: BUS_DMASYNC_PREREAD |
1057: BUS_DMASYNC_PREWRITE);
1058: }
1.9 thorpej 1059: } else if (__predict_true((ic =
1060: SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL)) {
1061: if ((*icp->icp_test_busy)(icp))
1062: break;
1063: } else {
1064: /* no command found */
1.1 ad 1065: break;
1.9 thorpej 1066: }
1.1 ad 1067: icp_ccb_submit(icp, ic);
1.8 thorpej 1068: if (__predict_false((ic->ic_flags & IC_UCMD) != 0))
1069: SIMPLEQ_REMOVE_HEAD(&icp->icp_ucmd_queue, ic_chain);
1070: else
1071: SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic_chain);
1.1 ad 1072: }
1073:
1074: splx(s);
1075: }
1076:
1077: int
1078: icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
1079: int dir)
1080: {
1081: struct icp_sg *sg;
1082: int nsegs, i, rv;
1083: bus_dmamap_t xfer;
1084:
1085: xfer = ic->ic_xfer_map;
1086:
1087: rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
1088: BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
1089: ((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
1090: if (rv != 0)
1091: return (rv);
1092:
1093: nsegs = xfer->dm_nsegs;
1094: ic->ic_xfer_size = size;
1095: ic->ic_nsgent = nsegs;
1096: ic->ic_flags |= dir;
1097: sg = ic->ic_sg;
1098:
1099: if (sg != NULL) {
1100: for (i = 0; i < nsegs; i++, sg++) {
1101: sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
1102: sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
1103: }
1104: } else if (nsegs > 1)
1.4 provos 1105: panic("icp_ccb_map: no SG list specified, but nsegs > 1");
1.1 ad 1106:
1107: if ((dir & IC_XFER_OUT) != 0)
1108: i = BUS_DMASYNC_PREWRITE;
1109: else /* if ((dir & IC_XFER_IN) != 0) */
1110: i = BUS_DMASYNC_PREREAD;
1111:
1112: bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
1113: return (0);
1114: }
1115:
1116: void
1117: icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
1118: {
1119: int i;
1120:
1121: if ((ic->ic_flags & IC_XFER_OUT) != 0)
1122: i = BUS_DMASYNC_POSTWRITE;
1123: else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
1124: i = BUS_DMASYNC_POSTREAD;
1125:
1126: bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
1127: bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
1128: }
1129:
1130: int
1131: icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
1132: {
1.10 thorpej 1133: int s, rv;
1134:
1135: s = splbio();
1.1 ad 1136:
1137: for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
1138: if (!(*icp->icp_test_busy)(icp))
1139: break;
1140: DELAY(10);
1141: }
1142: if (timo == 0) {
1.27 cegger 1143: printf("%s: submit: busy\n", device_xname(&icp->icp_dv));
1.1 ad 1144: return (EAGAIN);
1145: }
1146:
1147: icp_ccb_submit(icp, ic);
1148:
1.10 thorpej 1149: if (cold) {
1150: for (timo *= 10; timo != 0; timo--) {
1151: DELAY(100);
1152: icp_intr(icp);
1153: if ((ic->ic_flags & IC_COMPLETE) != 0)
1154: break;
1155: }
1156: } else {
1157: ic->ic_flags |= IC_WAITING;
1158: while ((ic->ic_flags & IC_COMPLETE) == 0) {
1159: if ((rv = tsleep(ic, PRIBIO, "icpwccb",
1160: mstohz(timo))) != 0) {
1161: timo = 0;
1162: break;
1163: }
1164: }
1.1 ad 1165: }
1166:
1167: if (timo != 0) {
1168: if (ic->ic_status != ICP_S_OK) {
1169: #ifdef ICP_DEBUG
1170: printf("%s: request failed; status=0x%04x\n",
1.27 cegger 1171: device_xname(&icp->icp_dv), ic->ic_status);
1.1 ad 1172: #endif
1173: rv = EIO;
1174: } else
1175: rv = 0;
1176: } else {
1.27 cegger 1177: aprint_error_dev(&icp->icp_dv, "command timed out\n");
1.1 ad 1178: rv = EIO;
1179: }
1180:
1181: while ((*icp->icp_test_busy)(icp) != 0)
1182: DELAY(10);
1183:
1.10 thorpej 1184: splx(s);
1185:
1.1 ad 1186: return (rv);
1187: }
1188:
1189: int
1190: icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
1191: {
1192: int s, rv;
1193:
1194: ic->ic_flags |= IC_WAITING;
1195:
1196: s = splbio();
1197: icp_ccb_enqueue(icp, ic);
1.8 thorpej 1198: while ((ic->ic_flags & IC_COMPLETE) == 0) {
1199: if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
1200: splx(s);
1201: return (rv);
1202: }
1.1 ad 1203: }
1204: splx(s);
1205:
1206: if (ic->ic_status != ICP_S_OK) {
1.27 cegger 1207: aprint_error_dev(&icp->icp_dv, "command failed; status=%x\n",
1.1 ad 1208: ic->ic_status);
1209: return (EIO);
1210: }
1211:
1212: return (0);
1213: }
1214:
1.8 thorpej 1215: int
1216: icp_ccb_wait_user(struct icp_softc *icp, struct icp_ccb *ic, int timo)
1217: {
1218: int s, rv;
1219:
1220: ic->ic_dv = &icp->icp_dv;
1221: ic->ic_intr = icp_ucmd_intr;
1222: ic->ic_flags |= IC_UCMD;
1223:
1224: s = splbio();
1225: icp_ccb_enqueue(icp, ic);
1226: while ((ic->ic_flags & IC_COMPLETE) == 0) {
1227: if ((rv = tsleep(ic, PRIBIO, "icpwuccb", mstohz(timo))) != 0) {
1228: splx(s);
1229: return (rv);
1230: }
1231: }
1232: splx(s);
1233:
1234: return (0);
1235: }
1236:
1.1 ad 1237: void
1238: icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
1239: {
1240:
1241: ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
1242:
1243: (*icp->icp_set_sema0)(icp);
1244: DELAY(10);
1245:
1246: ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
1247: ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
1248:
1.10 thorpej 1249: icp->icp_running++;
1250:
1.1 ad 1251: (*icp->icp_copy_cmd)(icp, ic);
1252: (*icp->icp_release_event)(icp, ic);
1.10 thorpej 1253: }
1254:
1255: int
1256: icp_freeze(struct icp_softc *icp)
1257: {
1258: int s, error = 0;
1259:
1260: s = splbio();
1261: if (icp->icp_qfreeze++ == 0) {
1262: while (icp->icp_running != 0) {
1263: icp->icp_flags |= ICP_F_WAIT_FREEZE;
1264: error = tsleep(&icp->icp_qfreeze, PRIBIO|PCATCH,
1265: "icpqfrz", 0);
1266: if (error != 0 && --icp->icp_qfreeze == 0 &&
1267: ICP_HAS_WORK(icp)) {
1268: icp_ccb_enqueue(icp, NULL);
1269: break;
1270: }
1271: }
1272: }
1273: splx(s);
1274:
1275: return (error);
1276: }
1277:
1278: void
1279: icp_unfreeze(struct icp_softc *icp)
1280: {
1281: int s;
1282:
1283: s = splbio();
1284: KDASSERT(icp->icp_qfreeze != 0);
1285: if (--icp->icp_qfreeze == 0 && ICP_HAS_WORK(icp))
1286: icp_ccb_enqueue(icp, NULL);
1287: splx(s);
1.8 thorpej 1288: }
1289:
1290: /* XXX Global - should be per-controller? XXX */
1291: static gdt_evt_str icp_event_buffer[ICP_MAX_EVENTS];
1292: static int icp_event_oldidx;
1293: static int icp_event_lastidx;
1294:
1295: gdt_evt_str *
1.22 christos 1296: icp_store_event(struct icp_softc *icp, u_int16_t source, u_int16_t idx,
1.8 thorpej 1297: gdt_evt_data *evt)
1298: {
1299: gdt_evt_str *e;
1300:
1301: /* no source == no event */
1302: if (source == 0)
1303: return (NULL);
1304:
1305: e = &icp_event_buffer[icp_event_lastidx];
1306: if (e->event_source == source && e->event_idx == idx &&
1307: ((evt->size != 0 && e->event_data.size != 0 &&
1308: memcmp(&e->event_data.eu, &evt->eu, evt->size) == 0) ||
1309: (evt->size == 0 && e->event_data.size == 0 &&
1310: strcmp((char *) e->event_data.event_string,
1311: (char *) evt->event_string) == 0))) {
1.20 kardel 1312: e->last_stamp = time_second;
1.8 thorpej 1313: e->same_count++;
1314: } else {
1315: if (icp_event_buffer[icp_event_lastidx].event_source != 0) {
1316: icp_event_lastidx++;
1317: if (icp_event_lastidx == ICP_MAX_EVENTS)
1318: icp_event_lastidx = 0;
1319: if (icp_event_lastidx == icp_event_oldidx) {
1320: icp_event_oldidx++;
1321: if (icp_event_oldidx == ICP_MAX_EVENTS)
1322: icp_event_oldidx = 0;
1323: }
1324: }
1325: e = &icp_event_buffer[icp_event_lastidx];
1326: e->event_source = source;
1327: e->event_idx = idx;
1.20 kardel 1328: e->first_stamp = e->last_stamp = time_second;
1.8 thorpej 1329: e->same_count = 1;
1330: e->event_data = *evt;
1331: e->application = 0;
1332: }
1333: return (e);
1334: }
1335:
1336: int
1.22 christos 1337: icp_read_event(struct icp_softc *icp, int handle, gdt_evt_str *estr)
1.8 thorpej 1338: {
1339: gdt_evt_str *e;
1340: int eindex, s;
1341:
1342: s = splbio();
1343:
1344: if (handle == -1)
1345: eindex = icp_event_oldidx;
1346: else
1347: eindex = handle;
1348:
1349: estr->event_source = 0;
1350:
1351: if (eindex < 0 || eindex >= ICP_MAX_EVENTS) {
1352: splx(s);
1353: return (eindex);
1354: }
1355:
1356: e = &icp_event_buffer[eindex];
1357: if (e->event_source != 0) {
1358: if (eindex != icp_event_lastidx) {
1359: eindex++;
1360: if (eindex == ICP_MAX_EVENTS)
1361: eindex = 0;
1362: } else
1363: eindex = -1;
1364: memcpy(estr, e, sizeof(gdt_evt_str));
1365: }
1366:
1367: splx(s);
1368:
1369: return (eindex);
1370: }
1371:
1372: void
1.22 christos 1373: icp_readapp_event(struct icp_softc *icp, u_int8_t application,
1.8 thorpej 1374: gdt_evt_str *estr)
1375: {
1376: gdt_evt_str *e;
1377: int found = 0, eindex, s;
1378:
1379: s = splbio();
1380:
1381: eindex = icp_event_oldidx;
1382: for (;;) {
1383: e = &icp_event_buffer[eindex];
1384: if (e->event_source == 0)
1385: break;
1386: if ((e->application & application) == 0) {
1387: e->application |= application;
1388: found = 1;
1389: break;
1390: }
1391: if (eindex == icp_event_lastidx)
1392: break;
1393: eindex++;
1394: if (eindex == ICP_MAX_EVENTS)
1395: eindex = 0;
1396: }
1397: if (found)
1398: memcpy(estr, e, sizeof(gdt_evt_str));
1399: else
1400: estr->event_source = 0;
1401:
1402: splx(s);
1403: }
1404:
1405: void
1.22 christos 1406: icp_clear_events(struct icp_softc *icp)
1.8 thorpej 1407: {
1408: int s;
1409:
1410: s = splbio();
1411: icp_event_oldidx = icp_event_lastidx = 0;
1412: memset(icp_event_buffer, 0, sizeof(icp_event_buffer));
1413: splx(s);
1.1 ad 1414: }
CVSweb <webmaster@jp.NetBSD.org>