kernel: Add descriptions to the intrhooks that miss them.
[dragonfly.git] / sys / dev / raid / twe / twe_freebsd.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 2000 Michael Smith
a062d8a7
HP
3 * Copyright (c) 2003 Paul Saab
4 * Copyright (c) 2003 Vinod Kashyap
984263bc
MD
5 * Copyright (c) 2000 BSDi
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
c2b68912 29 * $FreeBSD: src/sys/dev/twe/twe_freebsd.c,v 1.48 2009/12/25 17:34:43 mav Exp $
984263bc
MD
30 */
31
32/*
33 * FreeBSD-specific code.
34 */
35
a062d8a7
HP
36#include <dev/raid/twe/twe_compat.h>
37#include <dev/raid/twe/twereg.h>
a062d8a7
HP
38#include <dev/raid/twe/tweio.h>
39#include <dev/raid/twe/twevar.h>
c2b68912 40#include <dev/raid/twe/twe_tables.h>
ba0cc1ab 41#include <sys/dtype.h>
984263bc 42
c2b68912
SW
43#include <vm/vm.h>
44
984263bc
MD
45static devclass_t twe_devclass;
46
47#ifdef TWE_DEBUG
48static u_int32_t twed_bio_in;
49#define TWED_BIO_IN twed_bio_in++
50static u_int32_t twed_bio_out;
51#define TWED_BIO_OUT twed_bio_out++
52#else
53#define TWED_BIO_IN
54#define TWED_BIO_OUT
55#endif
56
c2b68912
SW
57static void twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
58static void twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
59
984263bc
MD
60/********************************************************************************
61 ********************************************************************************
62 Control device interface
63 ********************************************************************************
64 ********************************************************************************/
65
66static d_open_t twe_open;
67static d_close_t twe_close;
68static d_ioctl_t twe_ioctl_wrapper;
69
fef8985e 70static struct dev_ops twe_ops = {
88abd8b5 71 { "twe", 0, 0 },
fef8985e
MD
72 .d_open = twe_open,
73 .d_close = twe_close,
74 .d_ioctl = twe_ioctl_wrapper,
984263bc
MD
75};
76
77/********************************************************************************
78 * Accept an open operation on the control device.
79 */
80static int
fef8985e 81twe_open(struct dev_open_args *ap)
984263bc 82{
c2b68912
SW
83 cdev_t dev = ap->a_head.a_dev;
84 struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
984263bc
MD
85
86 sc->twe_state |= TWE_STATE_OPEN;
87 return(0);
88}
89
90/********************************************************************************
91 * Accept the last close on the control device.
92 */
93static int
fef8985e 94twe_close(struct dev_close_args *ap)
984263bc 95{
c2b68912
SW
96 cdev_t dev = ap->a_head.a_dev;
97 struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
984263bc
MD
98
99 sc->twe_state &= ~TWE_STATE_OPEN;
100 return (0);
101}
102
103/********************************************************************************
104 * Handle controller-specific control operations.
105 */
106static int
fef8985e 107twe_ioctl_wrapper(struct dev_ioctl_args *ap)
984263bc 108{
b13267a5 109 cdev_t dev = ap->a_head.a_dev;
c2b68912
SW
110 u_long cmd = ap->a_cmd;
111 caddr_t addr = ap->a_data;
fef8985e 112 struct twe_softc *sc = (struct twe_softc *)dev->si_drv1;
984263bc 113
c2b68912 114 return(twe_ioctl(sc, cmd, addr));
984263bc
MD
115}
116
117/********************************************************************************
118 ********************************************************************************
119 PCI device interface
120 ********************************************************************************
121 ********************************************************************************/
122
123static int twe_probe(device_t dev);
124static int twe_attach(device_t dev);
125static void twe_free(struct twe_softc *sc);
126static int twe_detach(device_t dev);
a062d8a7 127static int twe_shutdown(device_t dev);
984263bc
MD
128static int twe_suspend(device_t dev);
129static int twe_resume(device_t dev);
130static void twe_pci_intr(void *arg);
131static void twe_intrhook(void *arg);
132
133static device_method_t twe_methods[] = {
134 /* Device interface */
135 DEVMETHOD(device_probe, twe_probe),
136 DEVMETHOD(device_attach, twe_attach),
137 DEVMETHOD(device_detach, twe_detach),
138 DEVMETHOD(device_shutdown, twe_shutdown),
139 DEVMETHOD(device_suspend, twe_suspend),
140 DEVMETHOD(device_resume, twe_resume),
141
142 DEVMETHOD(bus_print_child, bus_generic_print_child),
143 DEVMETHOD(bus_driver_added, bus_generic_driver_added),
144 { 0, 0 }
145};
146
147static driver_t twe_pci_driver = {
148 "twe",
149 twe_methods,
150 sizeof(struct twe_softc)
151};
152
aa2b9d05 153DRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, NULL, NULL);
984263bc
MD
154
155/********************************************************************************
156 * Match a 3ware Escalade ATA RAID controller.
157 */
158static int
159twe_probe(device_t dev)
160{
161
162 debug_called(4);
163
164 if ((pci_get_vendor(dev) == TWE_VENDOR_ID) &&
165 ((pci_get_device(dev) == TWE_DEVICE_ID) ||
166 (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) {
c2b68912
SW
167 device_set_desc_copy(dev, TWE_DEVICE_NAME ". Driver version " TWE_DRIVER_VERSION_STRING);
168 return(BUS_PROBE_DEFAULT);
984263bc
MD
169 }
170 return(ENXIO);
171}
172
173/********************************************************************************
174 * Allocate resources, initialise the controller.
175 */
176static int
177twe_attach(device_t dev)
178{
179 struct twe_softc *sc;
180 int rid, error;
181 u_int32_t command;
182
183 debug_called(4);
184
185 /*
186 * Initialise the softc structure.
187 */
188 sc = device_get_softc(dev);
189 sc->twe_dev = dev;
190
0a62b1be
DR
191 sysctl_ctx_init(&sc->sysctl_ctx);
192 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
193 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
194 device_get_nameunit(dev), CTLFLAG_RD, 0, "");
195 if (sc->sysctl_tree == NULL) {
196 twe_printf(sc, "cannot add sysctl tree node\n");
197 return (ENXIO);
198 }
199 SYSCTL_ADD_STRING(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
a062d8a7 200 OID_AUTO, "driver_version", CTLFLAG_RD, TWE_DRIVER_VERSION_STRING, 0,
0a62b1be
DR
201 "TWE driver version");
202
984263bc
MD
203 /*
204 * Make sure we are going to be able to talk to this board.
205 */
206 command = pci_read_config(dev, PCIR_COMMAND, 2);
207 if ((command & PCIM_CMD_PORTEN) == 0) {
208 twe_printf(sc, "register window not available\n");
209 return(ENXIO);
210 }
211 /*
212 * Force the busmaster enable bit on, in case the BIOS forgot.
213 */
214 command |= PCIM_CMD_BUSMASTEREN;
215 pci_write_config(dev, PCIR_COMMAND, command, 2);
216
217 /*
218 * Allocate the PCI register window.
219 */
220 rid = TWE_IO_CONFIG_REG;
c2b68912
SW
221 if ((sc->twe_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
222 RF_ACTIVE)) == NULL) {
984263bc
MD
223 twe_printf(sc, "can't allocate register window\n");
224 twe_free(sc);
225 return(ENXIO);
226 }
227 sc->twe_btag = rman_get_bustag(sc->twe_io);
228 sc->twe_bhandle = rman_get_bushandle(sc->twe_io);
229
230 /*
231 * Allocate the parent bus DMA tag appropriate for PCI.
232 */
233 if (bus_dma_tag_create(NULL, /* parent */
234 1, 0, /* alignment, boundary */
235 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
236 BUS_SPACE_MAXADDR, /* highaddr */
237 NULL, NULL, /* filter, filterarg */
238 MAXBSIZE, TWE_MAX_SGL_LENGTH, /* maxsize, nsegments */
239 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
c2b68912 240 0, /* flags */
984263bc
MD
241 &sc->twe_parent_dmat)) {
242 twe_printf(sc, "can't allocate parent DMA tag\n");
243 twe_free(sc);
244 return(ENOMEM);
245 }
246
247 /*
248 * Allocate and connect our interrupt.
249 */
250 rid = 0;
c2b68912
SW
251 if ((sc->twe_irq = bus_alloc_resource_any(sc->twe_dev, SYS_RES_IRQ,
252 &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
984263bc
MD
253 twe_printf(sc, "can't allocate interrupt\n");
254 twe_free(sc);
255 return(ENXIO);
256 }
8b3ec75a 257 if (bus_setup_intr(sc->twe_dev, sc->twe_irq, 0,
ee61f228 258 twe_pci_intr, sc, &sc->twe_intr, NULL)) {
984263bc
MD
259 twe_printf(sc, "can't set up interrupt\n");
260 twe_free(sc);
261 return(ENXIO);
262 }
263
264 /*
c2b68912
SW
265 * Create DMA tag for mapping command's into controller-addressable space.
266 */
267 if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */
268 1, 0, /* alignment, boundary */
269 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
270 BUS_SPACE_MAXADDR, /* highaddr */
271 NULL, NULL, /* filter, filterarg */
272 sizeof(TWE_Command) *
273 TWE_Q_LENGTH, 1, /* maxsize, nsegments */
274 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
275 0, /* flags */
276 &sc->twe_cmd_dmat)) {
277 twe_printf(sc, "can't allocate data buffer DMA tag\n");
278 twe_free(sc);
279 return(ENOMEM);
280 }
281 /*
282 * Allocate memory and make it available for DMA.
283 */
284 if (bus_dmamem_alloc(sc->twe_cmd_dmat, (void **)&sc->twe_cmd,
285 BUS_DMA_NOWAIT, &sc->twe_cmdmap)) {
286 twe_printf(sc, "can't allocate command memory\n");
287 return(ENOMEM);
288 }
289 bus_dmamap_load(sc->twe_cmd_dmat, sc->twe_cmdmap, sc->twe_cmd,
290 sizeof(TWE_Command) * TWE_Q_LENGTH,
291 twe_setup_request_dmamap, sc, 0);
292 bzero(sc->twe_cmd, sizeof(TWE_Command) * TWE_Q_LENGTH);
293
294 /*
984263bc
MD
295 * Create DMA tag for mapping objects into controller-addressable space.
296 */
297 if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */
298 1, 0, /* alignment, boundary */
c2b68912 299 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
984263bc
MD
300 BUS_SPACE_MAXADDR, /* highaddr */
301 NULL, NULL, /* filter, filterarg */
302 MAXBSIZE, TWE_MAX_SGL_LENGTH,/* maxsize, nsegments */
303 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
c2b68912 304 BUS_DMA_ALLOCNOW, /* flags */
984263bc
MD
305 &sc->twe_buffer_dmat)) {
306 twe_printf(sc, "can't allocate data buffer DMA tag\n");
307 twe_free(sc);
308 return(ENOMEM);
309 }
310
311 /*
c2b68912
SW
312 * Create DMA tag for mapping objects into controller-addressable space.
313 */
314 if (bus_dma_tag_create(sc->twe_parent_dmat, /* parent */
315 1, 0, /* alignment, boundary */
316 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
317 BUS_SPACE_MAXADDR, /* highaddr */
318 NULL, NULL, /* filter, filterarg */
319 MAXBSIZE, 1, /* maxsize, nsegments */
320 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
321 0, /* flags */
322 &sc->twe_immediate_dmat)) {
323 twe_printf(sc, "can't allocate data buffer DMA tag\n");
324 twe_free(sc);
325 return(ENOMEM);
326 }
327 /*
328 * Allocate memory for requests which cannot sleep or support continuation.
329 */
330 if (bus_dmamem_alloc(sc->twe_immediate_dmat, (void **)&sc->twe_immediate,
331 BUS_DMA_NOWAIT, &sc->twe_immediate_map)) {
332 twe_printf(sc, "can't allocate memory for immediate requests\n");
333 return(ENOMEM);
334 }
335
336 /*
984263bc
MD
337 * Initialise the controller and driver core.
338 */
a062d8a7
HP
339 if ((error = twe_setup(sc))) {
340 twe_free(sc);
984263bc 341 return(error);
a062d8a7 342 }
984263bc
MD
343
344 /*
345 * Print some information about the controller and configuration.
346 */
347 twe_describe_controller(sc);
348
349 /*
350 * Create the control device.
351 */
fef8985e 352 sc->twe_dev_t = make_dev(&twe_ops, device_get_unit(sc->twe_dev),
3e82b46c
MD
353 UID_ROOT, GID_OPERATOR,
354 S_IRUSR | S_IWUSR, "twe%d",
355 device_get_unit(sc->twe_dev));
a062d8a7 356 sc->twe_dev_t->si_drv1 = sc;
3e82b46c 357
984263bc 358 /*
3e82b46c
MD
359 * Schedule ourselves to bring the controller up once interrupts are
360 * available. This isn't strictly necessary, since we disable
361 * interrupts while probing the controller, but it is more in keeping
362 * with common practice for other disk devices.
984263bc
MD
363 */
364 sc->twe_ich.ich_func = twe_intrhook;
365 sc->twe_ich.ich_arg = sc;
52800c9d 366 sc->twe_ich.ich_desc = "twe";
984263bc
MD
367 if (config_intrhook_establish(&sc->twe_ich) != 0) {
368 twe_printf(sc, "can't establish configuration hook\n");
369 twe_free(sc);
370 return(ENXIO);
371 }
372
373 return(0);
374}
375
376/********************************************************************************
377 * Free all of the resources associated with (sc).
378 *
379 * Should not be called if the controller is active.
380 */
381static void
382twe_free(struct twe_softc *sc)
383{
384 struct twe_request *tr;
385
386 debug_called(4);
387
388 /* throw away any command buffers */
389 while ((tr = twe_dequeue_free(sc)) != NULL)
390 twe_free_request(tr);
391
c2b68912
SW
392 if (sc->twe_cmd != NULL) {
393 bus_dmamap_unload(sc->twe_cmd_dmat, sc->twe_cmdmap);
394 bus_dmamem_free(sc->twe_cmd_dmat, sc->twe_cmd, sc->twe_cmdmap);
395 }
396
397 if (sc->twe_immediate != NULL) {
398 bus_dmamap_unload(sc->twe_immediate_dmat, sc->twe_immediate_map);
399 bus_dmamem_free(sc->twe_immediate_dmat, sc->twe_immediate,
400 sc->twe_immediate_map);
401 }
402
403 if (sc->twe_immediate_dmat)
404 bus_dma_tag_destroy(sc->twe_immediate_dmat);
405
984263bc
MD
406 /* destroy the data-transfer DMA tag */
407 if (sc->twe_buffer_dmat)
408 bus_dma_tag_destroy(sc->twe_buffer_dmat);
409
410 /* disconnect the interrupt handler */
411 if (sc->twe_intr)
412 bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr);
413 if (sc->twe_irq != NULL)
414 bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq);
415
416 /* destroy the parent DMA tag */
417 if (sc->twe_parent_dmat)
418 bus_dma_tag_destroy(sc->twe_parent_dmat);
419
420 /* release the register window mapping */
421 if (sc->twe_io != NULL)
422 bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io);
423
a062d8a7 424 /* destroy control device */
a60655aa 425 if (sc->twe_dev_t != NULL)
a062d8a7 426 destroy_dev(sc->twe_dev_t);
5f31229c 427 dev_ops_remove_minor(&twe_ops, device_get_unit(sc->twe_dev));
0a62b1be
DR
428
429 sysctl_ctx_free(&sc->sysctl_ctx);
984263bc
MD
430}
431
432/********************************************************************************
433 * Disconnect from the controller completely, in preparation for unload.
434 */
435static int
436twe_detach(device_t dev)
437{
438 struct twe_softc *sc = device_get_softc(dev);
5eb77fd5 439 int error;
984263bc
MD
440
441 debug_called(4);
442
443 error = EBUSY;
5eb77fd5 444 crit_enter();
984263bc
MD
445 if (sc->twe_state & TWE_STATE_OPEN)
446 goto out;
447
448 /*
449 * Shut the controller down.
450 */
c2b68912 451 if (twe_shutdown(dev))
a062d8a7 452 goto out;
984263bc
MD
453
454 twe_free(sc);
455
456 error = 0;
457 out:
5eb77fd5 458 crit_exit();
984263bc
MD
459 return(error);
460}
461
462/********************************************************************************
463 * Bring the controller down to a dormant state and detach all child devices.
464 *
465 * Note that we can assume that the bioq on the controller is empty, as we won't
466 * allow shutdown if any device is open.
467 */
a062d8a7 468static int
984263bc
MD
469twe_shutdown(device_t dev)
470{
471 struct twe_softc *sc = device_get_softc(dev);
a062d8a7 472 int i, error = 0;
984263bc
MD
473
474 debug_called(4);
475
5eb77fd5 476 crit_enter();
984263bc
MD
477
478 /*
479 * Delete all our child devices.
480 */
481 for (i = 0; i < TWE_MAX_UNITS; i++) {
c2b68912
SW
482 if (sc->twe_drive[i].td_disk != 0) {
483 if ((error = twe_detach_drive(sc, i)) != 0)
484 goto out;
485 }
984263bc
MD
486 }
487
488 /*
489 * Bring the controller down.
490 */
491 twe_deinit(sc);
492
c2b68912 493out:
5eb77fd5 494 crit_exit();
a062d8a7 495 return(error);
984263bc
MD
496}
497
498/********************************************************************************
499 * Bring the controller to a quiescent state, ready for system suspend.
500 */
501static int
502twe_suspend(device_t dev)
503{
504 struct twe_softc *sc = device_get_softc(dev);
984263bc
MD
505
506 debug_called(4);
507
5eb77fd5 508 crit_enter();
984263bc
MD
509 sc->twe_state |= TWE_STATE_SUSPEND;
510
511 twe_disable_interrupts(sc);
5eb77fd5 512 crit_exit();
984263bc
MD
513
514 return(0);
515}
516
517/********************************************************************************
518 * Bring the controller back to a state ready for operation.
519 */
520static int
521twe_resume(device_t dev)
522{
523 struct twe_softc *sc = device_get_softc(dev);
524
525 debug_called(4);
526
527 sc->twe_state &= ~TWE_STATE_SUSPEND;
528 twe_enable_interrupts(sc);
529
530 return(0);
531}
532
533/*******************************************************************************
534 * Take an interrupt, or be poked by other code to look for interrupt-worthy
535 * status.
536 */
537static void
538twe_pci_intr(void *arg)
539{
540 twe_intr((struct twe_softc *)arg);
541}
542
543/********************************************************************************
544 * Delayed-startup hook
545 */
546static void
547twe_intrhook(void *arg)
548{
549 struct twe_softc *sc = (struct twe_softc *)arg;
550
551 /* pull ourselves off the intrhook chain */
552 config_intrhook_disestablish(&sc->twe_ich);
553
554 /* call core startup routine */
555 twe_init(sc);
556}
557
558/********************************************************************************
559 * Given a detected drive, attach it to the bio interface.
560 *
0a62b1be 561 * This is called from twe_add_unit.
984263bc 562 */
a062d8a7 563int
984263bc
MD
564twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
565{
566 char buf[80];
c2b68912 567 int error;
984263bc
MD
568
569 dr->td_disk = device_add_child(sc->twe_dev, NULL, -1);
570 if (dr->td_disk == NULL) {
a062d8a7
HP
571 twe_printf(sc, "Cannot add unit\n");
572 return (EIO);
984263bc
MD
573 }
574 device_set_ivars(dr->td_disk, dr);
575
576 /*
577 * XXX It would make sense to test the online/initialising bits, but they seem to be
578 * always set...
579 */
f8c7a42d 580 ksprintf(buf, "Unit %d, %s, %s",
a062d8a7 581 dr->td_twe_unit,
0a62b1be 582 twe_describe_code(twe_table_unittype, dr->td_type),
984263bc
MD
583 twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK));
584 device_set_desc_copy(dr->td_disk, buf);
585
a062d8a7
HP
586 if ((error = bus_generic_attach(sc->twe_dev)) != 0) {
587 twe_printf(sc, "Cannot attach unit to controller. error = %d\n", error);
c2b68912 588 return (EIO);
a062d8a7 589 }
c2b68912 590 return (0);
984263bc
MD
591}
592
593/********************************************************************************
0a62b1be
DR
594 * Detach the specified unit if it exsists
595 *
596 * This is called from twe_del_unit.
597 */
a062d8a7 598int
0a62b1be
DR
599twe_detach_drive(struct twe_softc *sc, int unit)
600{
c2b68912 601 int error = 0;
0a62b1be 602
c2b68912
SW
603 if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[unit].td_disk)) != 0) {
604 twe_printf(sc, "failed to delete unit %d\n", unit);
605 return(error);
0a62b1be 606 }
a062d8a7 607 bzero(&sc->twe_drive[unit], sizeof(sc->twe_drive[unit]));
c2b68912 608 return(error);
0a62b1be
DR
609}
610
611/********************************************************************************
984263bc
MD
612 * Clear a PCI parity error.
613 */
614void
615twe_clear_pci_parity_error(struct twe_softc *sc)
616{
617 TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PARITY_ERROR);
618 pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PARITY_ERROR, 2);
619}
620
621/********************************************************************************
622 * Clear a PCI abort.
623 */
624void
625twe_clear_pci_abort(struct twe_softc *sc)
626{
627 TWE_CONTROL(sc, TWE_CONTROL_CLEAR_PCI_ABORT);
628 pci_write_config(sc->twe_dev, PCIR_STATUS, TWE_PCI_CLEAR_PCI_ABORT, 2);
629}
630
631/********************************************************************************
632 ********************************************************************************
633 Disk device
634 ********************************************************************************
635 ********************************************************************************/
636
637/*
984263bc
MD
638 * Disk device bus interface
639 */
640static int twed_probe(device_t dev);
641static int twed_attach(device_t dev);
642static int twed_detach(device_t dev);
643
644static device_method_t twed_methods[] = {
645 DEVMETHOD(device_probe, twed_probe),
646 DEVMETHOD(device_attach, twed_attach),
647 DEVMETHOD(device_detach, twed_detach),
648 { 0, 0 }
649};
650
651static driver_t twed_driver = {
652 "twed",
653 twed_methods,
654 sizeof(struct twed_softc)
655};
656
657static devclass_t twed_devclass;
aa2b9d05 658DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, NULL, NULL);
984263bc
MD
659
660/*
661 * Disk device control interface.
662 */
663static d_open_t twed_open;
664static d_close_t twed_close;
665static d_strategy_t twed_strategy;
666static d_dump_t twed_dump;
667
fef8985e 668static struct dev_ops twed_ops = {
88abd8b5 669 { "twed", 0, D_DISK },
fef8985e
MD
670 .d_open = twed_open,
671 .d_close = twed_close,
672 .d_read = physread,
673 .d_write = physwrite,
674 .d_strategy = twed_strategy,
675 .d_dump = twed_dump,
984263bc
MD
676};
677
984263bc
MD
678/********************************************************************************
679 * Handle open from generic layer.
680 *
681 * Note that this is typically only called by the diskslice code, and not
682 * for opens on subdevices (eg. slices, partitions).
683 */
684static int
fef8985e 685twed_open(struct dev_open_args *ap)
984263bc 686{
b13267a5 687 cdev_t dev = ap->a_head.a_dev;
984263bc 688 struct twed_softc *sc = (struct twed_softc *)dev->si_drv1;
984263bc
MD
689
690 debug_called(4);
691
692 if (sc == NULL)
693 return (ENXIO);
694
695 /* check that the controller is up and running */
696 if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN)
697 return(ENXIO);
a688b15c 698
984263bc
MD
699 sc->twed_flags |= TWED_OPEN;
700 return (0);
701}
702
703/********************************************************************************
704 * Handle last close of the disk device.
705 */
706static int
fef8985e 707twed_close(struct dev_close_args *ap)
984263bc 708{
b13267a5 709 cdev_t dev = ap->a_head.a_dev;
984263bc
MD
710 struct twed_softc *sc = (struct twed_softc *)dev->si_drv1;
711
712 debug_called(4);
713
714 if (sc == NULL)
715 return (ENXIO);
716
717 sc->twed_flags &= ~TWED_OPEN;
718 return (0);
719}
720
721/********************************************************************************
722 * Handle an I/O request.
723 */
fef8985e
MD
724static int
725twed_strategy(struct dev_strategy_args *ap)
984263bc 726{
b13267a5 727 cdev_t dev = ap->a_head.a_dev;
fef8985e 728 struct bio *bio = ap->a_bio;
81b5c339
MD
729 struct twed_softc *sc = dev->si_drv1;
730 struct buf *bp = bio->bio_buf;
731
732 bio->bio_driver_info = sc;
984263bc
MD
733
734 debug_called(4);
735
736 TWED_BIO_IN;
737
738 /* bogus disk? */
c2b68912 739 if (sc == NULL || sc->twed_drive->td_disk == NULL) {
81b5c339
MD
740 bp->b_error = EINVAL;
741 bp->b_flags |= B_ERROR;
e3869ec7 742 kprintf("twe: bio for invalid disk!\n");
81b5c339 743 biodone(bio);
984263bc 744 TWED_BIO_OUT;
fef8985e 745 return(0);
984263bc
MD
746 }
747
748 /* perform accounting */
81b5c339 749 devstat_start_transaction(&sc->twed_stats);
984263bc
MD
750
751 /* queue the bio on the controller */
81b5c339 752 twe_enqueue_bio(sc->twed_controller, bio);
984263bc
MD
753
754 /* poke the controller to start I/O */
755 twe_startio(sc->twed_controller);
fef8985e 756 return(0);
984263bc
MD
757}
758
759/********************************************************************************
760 * System crashdump support
761 */
a062d8a7 762static int
fef8985e 763twed_dump(struct dev_dump_args *ap)
984263bc 764{
b13267a5 765 cdev_t dev = ap->a_head.a_dev;
c2b68912
SW
766 size_t length = ap->a_length;
767 off_t offset = ap->a_offset;
768 void *virtual = ap->a_virtual;
769 struct twed_softc *twed_sc;
770 struct twe_softc *twe_sc;
984263bc 771 int error;
984263bc 772
c2b68912
SW
773 twed_sc = dev->si_drv1;
774 if (twed_sc == NULL)
984263bc 775 return(ENXIO);
c2b68912 776 twe_sc = (struct twe_softc *)twed_sc->twed_controller;
984263bc 777
c2b68912
SW
778 if (length > 0) {
779 if ((error = twe_dump_blocks(twe_sc, twed_sc->twed_drive->td_twe_unit, offset / TWE_BLOCK_SIZE, virtual, length / TWE_BLOCK_SIZE)) != 0)
984263bc 780 return(error);
984263bc
MD
781 }
782 return(0);
783}
784
785/********************************************************************************
786 * Handle completion of an I/O request.
787 */
788void
81b5c339 789twed_intr(struct bio *bio)
984263bc 790{
81b5c339
MD
791 struct buf *bp = bio->bio_buf;
792 struct twed_softc *sc = bio->bio_driver_info;
c2b68912 793
984263bc
MD
794 debug_called(4);
795
796 /* if no error, transfer completed */
24aa53aa 797 if ((bp->b_flags & B_ERROR) == 0)
81b5c339
MD
798 bp->b_resid = 0;
799 devstat_end_transaction_buf(&sc->twed_stats, bp);
800 biodone(bio);
984263bc
MD
801 TWED_BIO_OUT;
802}
803
804/********************************************************************************
805 * Default probe stub.
806 */
807static int
808twed_probe(device_t dev)
809{
810 return (0);
811}
812
813/********************************************************************************
814 * Attach a unit to the controller.
815 */
816static int
817twed_attach(device_t dev)
818{
819 struct twed_softc *sc;
c2b68912 820 struct disk_info info;
984263bc 821 device_t parent;
b13267a5 822 cdev_t dsk;
984263bc
MD
823
824 debug_called(4);
825
826 /* initialise our softc */
827 sc = device_get_softc(dev);
828 parent = device_get_parent(dev);
829 sc->twed_controller = (struct twe_softc *)device_get_softc(parent);
830 sc->twed_drive = device_get_ivars(dev);
831 sc->twed_dev = dev;
832
833 /* report the drive */
834 twed_printf(sc, "%uMB (%u sectors)\n",
835 sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE),
836 sc->twed_drive->td_size);
837
c2b68912
SW
838 /* attach a generic disk device to ourselves */
839
840 sc->twed_drive->td_sys_unit = device_get_unit(dev);
841
a062d8a7
HP
842 devstat_add_entry(&sc->twed_stats, "twed", sc->twed_drive->td_sys_unit,
843 TWE_BLOCK_SIZE,
844 DEVSTAT_NO_ORDERED_TAGS,
845 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
846 DEVSTAT_PRIORITY_ARRAY);
984263bc 847
a688b15c 848 dsk = disk_create(sc->twed_drive->td_sys_unit, &sc->twed_disk, &twed_ops);
984263bc 849 dsk->si_drv1 = sc;
984263bc 850 sc->twed_dev_t = dsk;
984263bc
MD
851
852 /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */
853 dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE;
854
c2b68912
SW
855 /*
856 * Set disk info, as it appears that all needed data is available already.
857 * Setting the disk info will also cause the probing to start.
858 */
cd29885a
MD
859 bzero(&info, sizeof(info));
860 info.d_media_blksize = TWE_BLOCK_SIZE; /* mandatory */
861 info.d_media_blocks = sc->twed_drive->td_size;
862
863 info.d_type = DTYPE_ESDI; /* optional */
864 info.d_secpertrack = sc->twed_drive->td_sectors;
865 info.d_nheads = sc->twed_drive->td_heads;
866 info.d_ncylinders = sc->twed_drive->td_cylinders;
867 info.d_secpercyl = sc->twed_drive->td_sectors * sc->twed_drive->td_heads;
868
869 disk_setdiskinfo(&sc->twed_disk, &info);
870
984263bc
MD
871 return (0);
872}
873
874/********************************************************************************
875 * Disconnect ourselves from the system.
876 */
877static int
878twed_detach(device_t dev)
879{
880 struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev);
881
882 debug_called(4);
883
884 if (sc->twed_flags & TWED_OPEN)
885 return(EBUSY);
886
887 devstat_remove_entry(&sc->twed_stats);
335dda38 888 disk_destroy(&sc->twed_disk);
984263bc
MD
889
890 return(0);
891}
892
893/********************************************************************************
894 ********************************************************************************
895 Misc
896 ********************************************************************************
897 ********************************************************************************/
898
984263bc 899/********************************************************************************
a062d8a7 900 * Allocate a command buffer
984263bc 901 */
c2b68912
SW
902MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe_commands", "twe commands");
903
984263bc 904struct twe_request *
c2b68912 905twe_allocate_request(struct twe_softc *sc, int tag)
984263bc
MD
906{
907 struct twe_request *tr;
a062d8a7 908 int aligned_size;
984263bc 909
c4f9937c
MD
910 /*
911 * TWE requires requests to be 512-byte aligned. Depend on malloc()
912 * guarenteeing alignment for power-of-2 requests. Note that the old
913 * (FreeBSD-4.x) malloc code aligned all requests, but the new slab
914 * allocator only guarentees same-size alignment for power-of-2 requests.
915 */
916 aligned_size = (sizeof(struct twe_request) + TWE_ALIGNMASK) &
a062d8a7 917 ~TWE_ALIGNMASK;
efda3bd0 918 tr = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT|M_ZERO);
984263bc 919 tr->tr_sc = sc;
c2b68912 920 tr->tr_tag = tag;
984263bc 921 if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) {
984263bc 922 twe_free_request(tr);
c2b68912 923 twe_printf(sc, "unable to allocate dmamap for tag %d\n", tag);
984263bc
MD
924 return(NULL);
925 }
926 return(tr);
927}
928
929/********************************************************************************
930 * Permanently discard a command buffer.
931 */
c2b68912 932void
984263bc
MD
933twe_free_request(struct twe_request *tr)
934{
935 struct twe_softc *sc = tr->tr_sc;
936
937 debug_called(4);
938
984263bc 939 bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap);
efda3bd0 940 kfree(tr, TWE_MALLOC_CLASS);
984263bc
MD
941}
942
943/********************************************************************************
944 * Map/unmap (tr)'s command and data in the controller's addressable space.
945 *
946 * These routines ensure that the data which the controller is going to try to
947 * access is actually visible to the controller, in a machine-independant
948 * fashion. Due to a hardware limitation, I/O buffers must be 512-byte aligned
949 * and we take care of that here as well.
950 */
951static void
0a62b1be
DR
952twe_fillin_sgl(TWE_SG_Entry *sgl, bus_dma_segment_t *segs, int nsegments, int max_sgl)
953{
954 int i;
955
956 for (i = 0; i < nsegments; i++) {
957 sgl[i].address = segs[i].ds_addr;
958 sgl[i].length = segs[i].ds_len;
959 }
960 for (; i < max_sgl; i++) { /* XXX necessary? */
961 sgl[i].address = 0;
962 sgl[i].length = 0;
963 }
964}
965
966static void
984263bc
MD
967twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
968{
969 struct twe_request *tr = (struct twe_request *)arg;
c2b68912
SW
970 struct twe_softc *sc = tr->tr_sc;
971 TWE_Command *cmd = TWE_FIND_COMMAND(tr);
984263bc
MD
972
973 debug_called(4);
974
a062d8a7
HP
975 if (tr->tr_flags & TWE_CMD_MAPPED)
976 panic("already mapped command");
977
978 tr->tr_flags |= TWE_CMD_MAPPED;
979
980 if (tr->tr_flags & TWE_CMD_IN_PROGRESS)
c2b68912 981 sc->twe_state &= ~TWE_STATE_FRZN;
984263bc
MD
982 /* save base of first segment in command (applicable if there only one segment) */
983 tr->tr_dataphys = segs[0].ds_addr;
984
985 /* correct command size for s/g list size */
c2b68912 986 cmd->generic.size += 2 * nsegments;
984263bc
MD
987
988 /*
989 * Due to the fact that parameter and I/O commands have the scatter/gather list in
990 * different places, we need to determine which sort of command this actually is
991 * before we can populate it correctly.
992 */
993 switch(cmd->generic.opcode) {
994 case TWE_OP_GET_PARAM:
995 case TWE_OP_SET_PARAM:
996 cmd->generic.sgl_offset = 2;
0a62b1be 997 twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH);
984263bc
MD
998 break;
999 case TWE_OP_READ:
1000 case TWE_OP_WRITE:
1001 cmd->generic.sgl_offset = 3;
0a62b1be 1002 twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH);
984263bc 1003 break;
0a62b1be
DR
1004 case TWE_OP_ATA_PASSTHROUGH:
1005 cmd->generic.sgl_offset = 5;
1006 twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH);
6b08710e 1007 break;
0a62b1be
DR
1008 default:
1009 /*
1010 * Fall back to what the linux driver does.
1011 * Do this because the API may send an opcode
1012 * the driver knows nothing about and this will
1013 * at least stop PCIABRT's from hosing us.
1014 */
1015 switch (cmd->generic.sgl_offset) {
1016 case 2:
1017 twe_fillin_sgl(&cmd->param.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH);
1018 break;
1019 case 3:
1020 twe_fillin_sgl(&cmd->io.sgl[0], segs, nsegments, TWE_MAX_SGL_LENGTH);
1021 break;
1022 case 5:
1023 twe_fillin_sgl(&cmd->ata.sgl[0], segs, nsegments, TWE_MAX_ATA_SGL_LENGTH);
1024 break;
1025 }
984263bc 1026 }
c2b68912
SW
1027
1028 if (tr->tr_flags & TWE_CMD_DATAIN) {
1029 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1030 bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map,
1031 BUS_DMASYNC_PREREAD);
1032 } else {
1033 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap,
1034 BUS_DMASYNC_PREREAD);
1035 }
1036 }
1037
a062d8a7 1038 if (tr->tr_flags & TWE_CMD_DATAOUT) {
c2b68912
SW
1039 /*
1040 * if we're using an alignment buffer, and we're writing data
1041 * copy the real data out
1042 */
a062d8a7
HP
1043 if (tr->tr_flags & TWE_CMD_ALIGNBUF)
1044 bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length);
c2b68912
SW
1045
1046 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1047 bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map,
1048 BUS_DMASYNC_PREWRITE);
1049 } else {
1050 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap,
1051 BUS_DMASYNC_PREWRITE);
1052 }
a062d8a7 1053 }
c2b68912 1054
a062d8a7
HP
1055 if (twe_start(tr) == EBUSY) {
1056 tr->tr_sc->twe_state |= TWE_STATE_CTLR_BUSY;
1057 twe_requeue_ready(tr);
1058 }
984263bc
MD
1059}
1060
1061static void
1062twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
1063{
c2b68912 1064 struct twe_softc *sc = (struct twe_softc *)arg;
984263bc
MD
1065
1066 debug_called(4);
1067
1068 /* command can't cross a page boundary */
c2b68912 1069 sc->twe_cmdphys = segs[0].ds_addr;
984263bc
MD
1070}
1071
a062d8a7 1072int
984263bc
MD
1073twe_map_request(struct twe_request *tr)
1074{
1075 struct twe_softc *sc = tr->tr_sc;
a062d8a7 1076 int error = 0;
984263bc
MD
1077
1078 debug_called(4);
1079
a062d8a7
HP
1080 if (sc->twe_state & (TWE_STATE_CTLR_BUSY | TWE_STATE_FRZN)) {
1081 twe_requeue_ready(tr);
1082 return (EBUSY);
1083 }
984263bc 1084
c2b68912 1085 bus_dmamap_sync(sc->twe_cmd_dmat, sc->twe_cmdmap, BUS_DMASYNC_PREWRITE);
984263bc
MD
1086
1087 /*
1088 * If the command involves data, map that too.
1089 */
c2b68912 1090 if (tr->tr_data != NULL && ((tr->tr_flags & TWE_CMD_MAPPED) == 0)) {
984263bc
MD
1091
1092 /*
c4f9937c 1093 * Data must be 512-byte aligned; allocate a fixup buffer if it's not.
a2f0dcc5
MD
1094 *
1095 * DragonFly's malloc only guarentees alignment for requests which
1096 * are power-of-2 sized.
984263bc
MD
1097 */
1098 if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) {
a2f0dcc5 1099 int aligned_size;
c4f9937c 1100
a062d8a7 1101 tr->tr_realdata = tr->tr_data; /* save pointer to 'real' data */
a2f0dcc5
MD
1102 aligned_size = TWE_ALIGNMENT;
1103 while (aligned_size < tr->tr_length)
1104 aligned_size <<= 1;
984263bc 1105 tr->tr_flags |= TWE_CMD_ALIGNBUF;
efda3bd0 1106 tr->tr_data = kmalloc(aligned_size, TWE_MALLOC_CLASS, M_INTWAIT);
a062d8a7
HP
1107 if (tr->tr_data == NULL) {
1108 twe_printf(sc, "%s: malloc failed\n", __func__);
1109 tr->tr_data = tr->tr_realdata; /* restore original data pointer */
1110 return(ENOMEM);
1111 }
984263bc
MD
1112 }
1113
1114 /*
1115 * Map the data buffer into bus space and build the s/g list.
1116 */
c2b68912
SW
1117 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1118 error = bus_dmamap_load(sc->twe_immediate_dmat, sc->twe_immediate_map, sc->twe_immediate,
1119 tr->tr_length, twe_setup_data_dmamap, tr, BUS_DMA_NOWAIT);
1120 } else {
1121 error = bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length,
1122 twe_setup_data_dmamap, tr, 0);
1123 }
1124 if (error == EINPROGRESS) {
a062d8a7
HP
1125 tr->tr_flags |= TWE_CMD_IN_PROGRESS;
1126 sc->twe_state |= TWE_STATE_FRZN;
1127 error = 0;
1128 }
c2b68912 1129 } else
a062d8a7
HP
1130 if ((error = twe_start(tr)) == EBUSY) {
1131 sc->twe_state |= TWE_STATE_CTLR_BUSY;
1132 twe_requeue_ready(tr);
984263bc 1133 }
a062d8a7
HP
1134
1135 return(error);
984263bc
MD
1136}
1137
1138void
1139twe_unmap_request(struct twe_request *tr)
1140{
1141 struct twe_softc *sc = tr->tr_sc;
c2b68912 1142
984263bc
MD
1143 debug_called(4);
1144
c2b68912 1145 bus_dmamap_sync(sc->twe_cmd_dmat, sc->twe_cmdmap, BUS_DMASYNC_POSTWRITE);
984263bc
MD
1146
1147 /*
1148 * If the command involved data, unmap that too.
1149 */
1150 if (tr->tr_data != NULL) {
984263bc 1151 if (tr->tr_flags & TWE_CMD_DATAIN) {
c2b68912
SW
1152 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1153 bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map,
1154 BUS_DMASYNC_POSTREAD);
1155 } else {
1156 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap,
1157 BUS_DMASYNC_POSTREAD);
1158 }
1159
984263bc
MD
1160 /* if we're using an alignment buffer, and we're reading data, copy the real data in */
1161 if (tr->tr_flags & TWE_CMD_ALIGNBUF)
1162 bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length);
1163 }
c2b68912
SW
1164 if (tr->tr_flags & TWE_CMD_DATAOUT) {
1165 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1166 bus_dmamap_sync(sc->twe_immediate_dmat, sc->twe_immediate_map,
1167 BUS_DMASYNC_POSTWRITE);
1168 } else {
1169 bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap,
1170 BUS_DMASYNC_POSTWRITE);
1171 }
1172 }
984263bc 1173
c2b68912
SW
1174 if (tr->tr_flags & TWE_CMD_IMMEDIATE) {
1175 bus_dmamap_unload(sc->twe_immediate_dmat, sc->twe_immediate_map);
1176 } else {
1177 bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap);
1178 }
984263bc
MD
1179 }
1180
1181 /* free alignment buffer if it was used */
1182 if (tr->tr_flags & TWE_CMD_ALIGNBUF) {
efda3bd0 1183 kfree(tr->tr_data, TWE_MALLOC_CLASS);
984263bc
MD
1184 tr->tr_data = tr->tr_realdata; /* restore 'real' data pointer */
1185 }
1186}
1187
1188#ifdef TWE_DEBUG
a062d8a7 1189void twe_report(void);
984263bc
MD
1190/********************************************************************************
1191 * Print current controller status, call from DDB.
1192 */
1193void
1194twe_report(void)
1195{
1196 struct twe_softc *sc;
5eb77fd5 1197 int i;
984263bc 1198
5eb77fd5 1199 crit_enter();
984263bc
MD
1200 for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++)
1201 twe_print_controller(sc);
e3869ec7 1202 kprintf("twed: total bio count in %u out %u\n", twed_bio_in, twed_bio_out);
5eb77fd5 1203 crit_exit();
984263bc
MD
1204}
1205#endif