twe_freebsd.c revision 67684
1/*-
2 * Copyright (c) 2000 Michael Smith
3 * Copyright (c) 2000 BSDi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/dev/twe/twe_freebsd.c 67684 2000-10-27 05:58:45Z msmith $
28 */
29
30/*
31 * FreeBSD-specific code.
32 */
33
34#include <dev/twe/twe_compat.h>
35#include <dev/twe/twereg.h>
36#include <dev/twe/tweio.h>
37#include <dev/twe/twevar.h>
38#include <dev/twe/twe_tables.h>
39
40#include <sys/devicestat.h>
41
42static devclass_t	twe_devclass;
43
44/********************************************************************************
45 ********************************************************************************
46                                                         Control device interface
47 ********************************************************************************
48 ********************************************************************************/
49
50static	d_open_t		twe_open;
51static	d_close_t		twe_close;
52static	d_ioctl_t		twe_ioctl_wrapper;
53
54#define TWE_CDEV_MAJOR  146
55
56static struct cdevsw twe_cdevsw = {
57    twe_open,
58    twe_close,
59    noread,
60    nowrite,
61    twe_ioctl_wrapper,
62    nopoll,
63    nommap,
64    nostrategy,
65    "twe",
66    TWE_CDEV_MAJOR,
67    nodump,
68    nopsize,
69    0,
70    -1
71};
72
73/********************************************************************************
74 * Accept an open operation on the control device.
75 */
76static int
77twe_open(dev_t dev, int flags, int fmt, struct proc *p)
78{
79    int			unit = minor(dev);
80    struct twe_softc	*sc = devclass_get_softc(twe_devclass, unit);
81
82    sc->twe_state |= TWE_STATE_OPEN;
83    return(0);
84}
85
86/********************************************************************************
87 * Accept the last close on the control device.
88 */
89static int
90twe_close(dev_t dev, int flags, int fmt, struct proc *p)
91{
92    int			unit = minor(dev);
93    struct twe_softc	*sc = devclass_get_softc(twe_devclass, unit);
94
95    sc->twe_state &= ~TWE_STATE_OPEN;
96    return (0);
97}
98
99/********************************************************************************
100 * Handle controller-specific control operations.
101 */
102static int
103twe_ioctl_wrapper(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
104{
105    struct twe_softc		*sc = (struct twe_softc *)dev->si_drv1;
106
107    return(twe_ioctl(sc, cmd, addr));
108}
109
110/********************************************************************************
111 ********************************************************************************
112                                                             PCI device interface
113 ********************************************************************************
114 ********************************************************************************/
115
116static int	twe_probe(device_t dev);
117static int	twe_attach(device_t dev);
118static void	twe_free(struct twe_softc *sc);
119static int	twe_detach(device_t dev);
120static int	twe_shutdown(device_t dev);
121static int	twe_suspend(device_t dev);
122static int	twe_resume(device_t dev);
123static void	twe_pci_intr(void *arg);
124static void	twe_intrhook(void *arg);
125
126static device_method_t twe_methods[] = {
127    /* Device interface */
128    DEVMETHOD(device_probe,	twe_probe),
129    DEVMETHOD(device_attach,	twe_attach),
130    DEVMETHOD(device_detach,	twe_detach),
131    DEVMETHOD(device_shutdown,	twe_shutdown),
132    DEVMETHOD(device_suspend,	twe_suspend),
133    DEVMETHOD(device_resume,	twe_resume),
134
135    DEVMETHOD(bus_print_child,	bus_generic_print_child),
136    DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
137    { 0, 0 }
138};
139
140static driver_t twe_pci_driver = {
141	"twe",
142	twe_methods,
143	sizeof(struct twe_softc)
144};
145
146#ifdef TWE_OVERRIDE
147DRIVER_MODULE(Xtwe, pci, twe_pci_driver, twe_devclass, 0, 0);
148#else
149DRIVER_MODULE(twe, pci, twe_pci_driver, twe_devclass, 0, 0);
150#endif
151
152/********************************************************************************
153 * Match a 3ware Escalade ATA RAID controller.
154 */
155static int
156twe_probe(device_t dev)
157{
158
159    debug_called(4);
160
161    if ((pci_get_vendor(dev) == TWE_VENDOR_ID) &&
162	((pci_get_device(dev) == TWE_DEVICE_ID) ||
163	 (pci_get_device(dev) == TWE_DEVICE_ID_ASIC))) {
164	device_set_desc(dev, TWE_DEVICE_NAME);
165#ifdef TWE_OVERRIDE
166	return(0);
167#else
168	return(-10);
169#endif
170    }
171    return(ENXIO);
172}
173
174/********************************************************************************
175 * Allocate resources, initialise the controller.
176 */
177static int
178twe_attach(device_t dev)
179{
180    struct twe_softc	*sc;
181    int			rid, error;
182    u_int32_t		command;
183
184    debug_called(4);
185
186    /*
187     * Initialise the softc structure.
188     */
189    sc = device_get_softc(dev);
190    sc->twe_dev = dev;
191
192    /*
193     * Make sure we are going to be able to talk to this board.
194     */
195    command = pci_read_config(dev, PCIR_COMMAND, 2);
196    if ((command & PCIM_CMD_PORTEN) == 0) {
197	twe_printf(sc, "register window not available\n");
198	return(ENXIO);
199    }
200    /*
201     * Force the busmaster enable bit on, in case the BIOS forgot.
202     */
203    command |= PCIM_CMD_BUSMASTEREN;
204    pci_write_config(dev, PCIR_COMMAND, command, 2);
205
206    /*
207     * Allocate the PCI register window.
208     */
209    rid = TWE_IO_CONFIG_REG;
210    if ((sc->twe_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE)) == NULL) {
211	twe_printf(sc, "can't allocate register window\n");
212	twe_free(sc);
213	return(ENXIO);
214    }
215    sc->twe_btag = rman_get_bustag(sc->twe_io);
216    sc->twe_bhandle = rman_get_bushandle(sc->twe_io);
217
218    /*
219     * Allocate the parent bus DMA tag appropriate for PCI.
220     */
221    if (bus_dma_tag_create(NULL, 				/* parent */
222			   1, 0, 				/* alignment, boundary */
223			   BUS_SPACE_MAXADDR_32BIT, 		/* lowaddr */
224			   BUS_SPACE_MAXADDR, 			/* highaddr */
225			   NULL, NULL, 				/* filter, filterarg */
226			   MAXBSIZE, TWE_MAX_SGL_LENGTH,	/* maxsize, nsegments */
227			   BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
228			   BUS_DMA_ALLOCNOW,			/* flags */
229			   &sc->twe_parent_dmat)) {
230	twe_printf(sc, "can't allocate parent DMA tag\n");
231	twe_free(sc);
232	return(ENOMEM);
233    }
234
235    /*
236     * Allocate and connect our interrupt.
237     */
238    rid = 0;
239    if ((sc->twe_irq = bus_alloc_resource(sc->twe_dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
240	twe_printf(sc, "can't allocate interrupt\n");
241	twe_free(sc);
242	return(ENXIO);
243    }
244    if (bus_setup_intr(sc->twe_dev, sc->twe_irq, INTR_TYPE_BIO,  twe_pci_intr, sc, &sc->twe_intr)) {
245	twe_printf(sc, "can't set up interrupt\n");
246	twe_free(sc);
247	return(ENXIO);
248    }
249
250    /*
251     * Create DMA tag for mapping objects into controller-addressable space.
252     */
253    if (bus_dma_tag_create(sc->twe_parent_dmat, 		/* parent */
254			   1, 0, 				/* alignment, boundary */
255			   BUS_SPACE_MAXADDR,		/* lowaddr */
256			   BUS_SPACE_MAXADDR, 		/* highaddr */
257			   NULL, NULL, 			/* filter, filterarg */
258			   MAXBSIZE, TWE_MAX_SGL_LENGTH,	/* maxsize, nsegments */
259			   BUS_SPACE_MAXSIZE_32BIT,		/* maxsegsize */
260			   0,				/* flags */
261			   &sc->twe_buffer_dmat)) {
262	twe_printf(sc, "can't allocate data buffer DMA tag\n");
263	twe_free(sc);
264	return(ENOMEM);
265    }
266
267    /*
268     * Initialise the controller and driver core.
269     */
270    if ((error = twe_setup(sc)))
271	return(error);
272
273    /*
274     * Print some information about the controller and configuration.
275     */
276    twe_describe_controller(sc);
277
278    /*
279     * Create the control device.
280     */
281    sc->twe_dev_t = make_dev(&twe_cdevsw, device_get_unit(sc->twe_dev), UID_ROOT, GID_OPERATOR,
282			     S_IRUSR | S_IWUSR, "twe%d", device_get_unit(sc->twe_dev));
283    sc->twe_dev_t->si_drv1 = sc;
284    /*
285     * Schedule ourselves to bring the controller up once interrupts are available.
286     * This isn't strictly necessary, since we disable interrupts while probing the
287     * controller, but it is more in keeping with common practice for other disk
288     * devices.
289     */
290    sc->twe_ich.ich_func = twe_intrhook;
291    sc->twe_ich.ich_arg = sc;
292    if (config_intrhook_establish(&sc->twe_ich) != 0) {
293	twe_printf(sc, "can't establish configuration hook\n");
294	twe_free(sc);
295	return(ENXIO);
296    }
297
298    return(0);
299}
300
301/********************************************************************************
302 * Free all of the resources associated with (sc).
303 *
304 * Should not be called if the controller is active.
305 */
306static void
307twe_free(struct twe_softc *sc)
308{
309    struct twe_request	*tr;
310
311    debug_called(4);
312
313    /* throw away any command buffers */
314    while ((tr = twe_dequeue_free(sc)) != NULL)
315	twe_free_request(tr);
316
317    /* destroy the data-transfer DMA tag */
318    if (sc->twe_buffer_dmat)
319	bus_dma_tag_destroy(sc->twe_buffer_dmat);
320
321    /* disconnect the interrupt handler */
322    if (sc->twe_intr)
323	bus_teardown_intr(sc->twe_dev, sc->twe_irq, sc->twe_intr);
324    if (sc->twe_irq != NULL)
325	bus_release_resource(sc->twe_dev, SYS_RES_IRQ, 0, sc->twe_irq);
326
327    /* destroy the parent DMA tag */
328    if (sc->twe_parent_dmat)
329	bus_dma_tag_destroy(sc->twe_parent_dmat);
330
331    /* release the register window mapping */
332    if (sc->twe_io != NULL)
333	bus_release_resource(sc->twe_dev, SYS_RES_IOPORT, TWE_IO_CONFIG_REG, sc->twe_io);
334
335    /* destroy control device */
336    if (sc->twe_dev_t != (dev_t)NULL)
337	destroy_dev(sc->twe_dev_t);
338}
339
340/********************************************************************************
341 * Disconnect from the controller completely, in preparation for unload.
342 */
343static int
344twe_detach(device_t dev)
345{
346    struct twe_softc	*sc = device_get_softc(dev);
347    int			s, error;
348
349    debug_called(4);
350
351    error = EBUSY;
352    s = splbio();
353    if (sc->twe_state & TWE_STATE_OPEN)
354	goto out;
355
356    /*
357     * Shut the controller down.
358     */
359    if ((error = twe_shutdown(dev)))
360	goto out;
361
362    twe_free(sc);
363
364    error = 0;
365 out:
366    splx(s);
367    return(error);
368}
369
370/********************************************************************************
371 * Bring the controller down to a dormant state and detach all child devices.
372 *
373 * Note that we can assume that the bioq on the controller is empty, as we won't
374 * allow shutdown if any device is open.
375 */
376static int
377twe_shutdown(device_t dev)
378{
379    struct twe_softc	*sc = device_get_softc(dev);
380    int			i, s, error;
381
382    debug_called(4);
383
384    s = splbio();
385    error = 0;
386
387    /*
388     * Delete all our child devices.
389     */
390    for (i = 0; i < TWE_MAX_UNITS; i++) {
391	if (sc->twe_drive[i].td_disk != 0) {
392	    if ((error = device_delete_child(sc->twe_dev, sc->twe_drive[i].td_disk)) != 0)
393		goto out;
394	    sc->twe_drive[i].td_disk = 0;
395	}
396    }
397
398    /*
399     * Bring the controller down.
400     */
401    twe_deinit(sc);
402
403 out:
404    splx(s);
405    return(error);
406}
407
408/********************************************************************************
409 * Bring the controller to a quiescent state, ready for system suspend.
410 */
411static int
412twe_suspend(device_t dev)
413{
414    struct twe_softc	*sc = device_get_softc(dev);
415    int			s;
416
417    debug_called(4);
418
419    s = splbio();
420    sc->twe_state |= TWE_STATE_SUSPEND;
421
422    twe_disable_interrupts(sc);
423    splx(s);
424
425    return(0);
426}
427
428/********************************************************************************
429 * Bring the controller back to a state ready for operation.
430 */
431static int
432twe_resume(device_t dev)
433{
434    struct twe_softc	*sc = device_get_softc(dev);
435
436    debug_called(4);
437
438    sc->twe_state &= ~TWE_STATE_SUSPEND;
439    twe_enable_interrupts(sc);
440
441    return(0);
442}
443
444/*******************************************************************************
445 * Take an interrupt, or be poked by other code to look for interrupt-worthy
446 * status.
447 */
448static void
449twe_pci_intr(void *arg)
450{
451    twe_intr((struct twe_softc *)arg);
452}
453
454/********************************************************************************
455 * Delayed-startup hook
456 */
457static void
458twe_intrhook(void *arg)
459{
460    struct twe_softc		*sc = (struct twe_softc *)arg;
461
462    /* pull ourselves off the intrhook chain */
463    config_intrhook_disestablish(&sc->twe_ich);
464
465    /* call core startup routine */
466    twe_init(sc);
467}
468
469/********************************************************************************
470 * Given a detected drive, attach it to the bio interface.
471 *
472 * This is called from twe_init.
473 */
474void
475twe_attach_drive(struct twe_softc *sc, struct twe_drive *dr)
476{
477    char	buf[80];
478    int		error;
479
480    dr->td_disk =  device_add_child(sc->twe_dev, NULL, -1);
481    if (dr->td_disk == NULL) {
482	twe_printf(sc, "device_add_child failed\n");
483	return;
484    }
485    device_set_ivars(dr->td_disk, dr);
486
487    /*
488     * XXX It would make sense to test the online/initialising bits, but they seem to be
489     * always set...
490     */
491    sprintf(buf, "%s, %s", twe_describe_code(twe_table_unittype, dr->td_type),
492	    twe_describe_code(twe_table_unitstate, dr->td_state & TWE_PARAM_UNITSTATUS_MASK));
493    device_set_desc_copy(dr->td_disk, buf);
494
495    if ((error = bus_generic_attach(sc->twe_dev)) != 0)
496	twe_printf(sc, "bus_generic_attach returned %d\n", error);
497}
498
499/********************************************************************************
500 ********************************************************************************
501                                                                      Disk device
502 ********************************************************************************
503 ********************************************************************************/
504
505/*
506 * Disk device softc
507 */
508struct twed_softc
509{
510    device_t		twed_dev;
511    dev_t		twed_dev_t;
512    struct twe_softc	*twed_controller;	/* parent device softc */
513    struct twe_drive	*twed_drive;		/* drive data in parent softc */
514    struct disk		twed_disk;		/* generic disk handle */
515    struct devstat	twed_stats;		/* accounting */
516    struct disklabel	twed_label;		/* synthetic label */
517    int			twed_flags;
518#define TWED_OPEN	(1<<0)			/* drive is open (can't shut down) */
519};
520
521/*
522 * Disk device bus interface
523 */
524static int twed_probe(device_t dev);
525static int twed_attach(device_t dev);
526static int twed_detach(device_t dev);
527
528static device_method_t twed_methods[] = {
529    DEVMETHOD(device_probe,	twed_probe),
530    DEVMETHOD(device_attach,	twed_attach),
531    DEVMETHOD(device_detach,	twed_detach),
532    { 0, 0 }
533};
534
535static driver_t twed_driver = {
536    "twed",
537    twed_methods,
538    sizeof(struct twed_softc)
539};
540
541static devclass_t	twed_devclass;
542#ifdef TWE_OVERRIDE
543DRIVER_MODULE(Xtwed, Xtwe, twed_driver, twed_devclass, 0, 0);
544#else
545DRIVER_MODULE(twed, twe, twed_driver, twed_devclass, 0, 0);
546#endif
547
548/*
549 * Disk device control interface.
550 */
551static	d_open_t	twed_open;
552static	d_close_t	twed_close;
553static	d_strategy_t	twed_strategy;
554
555#define TWED_CDEV_MAJOR	147
556
557static struct cdevsw twed_cdevsw = {
558    twed_open,
559    twed_close,
560    physread,
561    physwrite,
562    noioctl,
563    nopoll,
564    nommap,
565    twed_strategy,
566    "twed",
567    TWED_CDEV_MAJOR,
568    nodump,
569    nopsize,
570    D_DISK,
571    -1
572};
573
574static struct cdevsw	tweddisk_cdevsw;
575#ifdef FREEBSD_4
576static int		disks_registered = 0;
577#endif
578
579/********************************************************************************
580 * Handle open from generic layer.
581 *
582 * Note that this is typically only called by the diskslice code, and not
583 * for opens on subdevices (eg. slices, partitions).
584 */
585static int
586twed_open(dev_t dev, int flags, int fmt, struct proc *p)
587{
588    struct twed_softc	*sc = (struct twed_softc *)dev->si_drv1;
589    struct disklabel	*label;
590
591    debug_called(4);
592
593    if (sc == NULL)
594	return (ENXIO);
595
596    /* check that the controller is up and running */
597    if (sc->twed_controller->twe_state & TWE_STATE_SHUTDOWN)
598	return(ENXIO);
599
600    /* build synthetic label */
601    label = &sc->twed_disk.d_label;
602    bzero(label, sizeof(*label));
603    label->d_type = DTYPE_ESDI;
604    label->d_secsize    = TWE_BLOCK_SIZE;
605    label->d_nsectors   = sc->twed_drive->td_sectors;
606    label->d_ntracks    = sc->twed_drive->td_heads;
607    label->d_ncylinders = sc->twed_drive->td_cylinders;
608    label->d_secpercyl  = sc->twed_drive->td_sectors * sc->twed_drive->td_heads;
609    label->d_secperunit = sc->twed_drive->td_size;
610
611    sc->twed_flags |= TWED_OPEN;
612    return (0);
613}
614
615/********************************************************************************
616 * Handle last close of the disk device.
617 */
618static int
619twed_close(dev_t dev, int flags, int fmt, struct proc *p)
620{
621    struct twed_softc	*sc = (struct twed_softc *)dev->si_drv1;
622
623    debug_called(4);
624
625    if (sc == NULL)
626	return (ENXIO);
627
628    sc->twed_flags &= ~TWED_OPEN;
629    return (0);
630}
631
632/********************************************************************************
633 * Handle an I/O request.
634 */
635static void
636twed_strategy(twe_bio *bp)
637{
638    struct twed_softc	*sc = (struct twed_softc *)TWE_BIO_SOFTC(bp);
639
640    debug_called(4);
641
642    /* bogus disk? */
643    if (sc == NULL) {
644	TWE_BIO_SET_ERROR(bp, EINVAL);
645	return;
646    }
647
648    /* do-nothing operation? */
649    if (TWE_BIO_LENGTH(bp) == 0) {
650	TWE_BIO_RESID(bp) = 0;
651	TWE_BIO_DONE(bp);
652	return;
653    }
654
655    /* perform accounting */
656    TWE_BIO_STATS_START(bp);
657
658    /* pass the bio to the controller - it can work out who we are */
659    twe_submit_bio(sc->twed_controller, bp);
660    return;
661}
662
663/********************************************************************************
664 * Handle completion of an I/O request.
665 */
666void
667twed_intr(twe_bio *bp)
668{
669    debug_called(4);
670
671    /* if no error, transfer completed */
672    if (!TWE_BIO_HAS_ERROR(bp))
673	TWE_BIO_RESID(bp) = 0;
674
675    TWE_BIO_STATS_END(bp);
676    TWE_BIO_DONE(bp);
677}
678
679/********************************************************************************
680 * Default probe stub.
681 */
682static int
683twed_probe(device_t dev)
684{
685    return (0);
686}
687
688/********************************************************************************
689 * Attach a unit to the controller.
690 */
691static int
692twed_attach(device_t dev)
693{
694    struct twed_softc	*sc;
695    device_t		parent;
696    dev_t		dsk;
697
698    debug_called(4);
699
700    /* initialise our softc */
701    sc = device_get_softc(dev);
702    parent = device_get_parent(dev);
703    sc->twed_controller = (struct twe_softc *)device_get_softc(parent);
704    sc->twed_drive = device_get_ivars(dev);
705    sc->twed_dev = dev;
706
707    /* report the drive */
708    twed_printf(sc, "%uMB (%u sectors)\n",
709		sc->twed_drive->td_size / ((1024 * 1024) / TWE_BLOCK_SIZE),
710		sc->twed_drive->td_size);
711
712    devstat_add_entry(&sc->twed_stats, "twed", device_get_unit(dev), TWE_BLOCK_SIZE,
713		      DEVSTAT_NO_ORDERED_TAGS,
714		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
715		      DEVSTAT_PRIORITY_ARRAY);
716
717    /* attach a generic disk device to ourselves */
718    dsk = disk_create(device_get_unit(dev), &sc->twed_disk, 0, &twed_cdevsw, &tweddisk_cdevsw);
719    dsk->si_drv1 = sc;
720    dsk->si_drv2 = &sc->twed_drive->td_unit;
721    sc->twed_dev_t = dsk;
722#ifdef FREEBSD_4
723    disks_registered++;
724#endif
725
726    /* set the maximum I/O size to the theoretical maximum allowed by the S/G list size */
727    dsk->si_iosize_max = (TWE_MAX_SGL_LENGTH - 1) * PAGE_SIZE;
728
729    return (0);
730}
731
732/********************************************************************************
733 * Disconnect ourselves from the system.
734 */
735static int
736twed_detach(device_t dev)
737{
738    struct twed_softc *sc = (struct twed_softc *)device_get_softc(dev);
739
740    debug_called(4);
741
742    if (sc->twed_flags & TWED_OPEN)
743	return(EBUSY);
744
745    devstat_remove_entry(&sc->twed_stats);
746#ifdef FREEBSD_4
747    if (--disks_registered == 0)
748	cdevsw_remove(&tweddisk_cdevsw);
749#else
750    disk_destroy(sc->twed_dev_t);
751#endif
752
753    return(0);
754}
755
756/********************************************************************************
757 ********************************************************************************
758                                                                             Misc
759 ********************************************************************************
760 ********************************************************************************/
761
762static void	twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
763static void	twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
764
765/********************************************************************************
766 * Allocate a command buffer
767 */
768MALLOC_DEFINE(TWE_MALLOC_CLASS, "twe commands", "twe commands");
769
770struct twe_request *
771twe_allocate_request(struct twe_softc *sc)
772{
773    struct twe_request	*tr;
774
775    if ((tr = malloc(sizeof(struct twe_request), TWE_MALLOC_CLASS, M_NOWAIT)) == NULL)
776	return(NULL);
777    bzero(tr, sizeof(*tr));
778    tr->tr_sc = sc;
779    if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_cmdmap)) {
780	twe_free_request(tr);
781	return(NULL);
782    }
783    if (bus_dmamap_create(sc->twe_buffer_dmat, 0, &tr->tr_dmamap)) {
784	bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap);
785	twe_free_request(tr);
786	return(NULL);
787    }
788    return(tr);
789}
790
791/********************************************************************************
792 * Permanently discard a command buffer.
793 */
794void
795twe_free_request(struct twe_request *tr)
796{
797    struct twe_softc	*sc = tr->tr_sc;
798
799    debug_called(4);
800
801    bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_cmdmap);
802    bus_dmamap_destroy(sc->twe_buffer_dmat, tr->tr_dmamap);
803    free(tr, TWE_MALLOC_CLASS);
804}
805
806/********************************************************************************
807 * Map/unmap (tr)'s command and data in the controller's addressable space.
808 *
809 * These routines ensure that the data which the controller is going to try to
810 * access is actually visible to the controller, in a machine-independant
811 * fasion.  Due to a hardware limitation, I/O buffers must be 512-byte aligned
812 * and we take care of that here as well.
813 */
814static void
815twe_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
816{
817    struct twe_request	*tr = (struct twe_request *)arg;
818    TWE_Command		*cmd = &tr->tr_command;
819    int			i;
820
821    debug_called(4);
822
823    /* save base of first segment in command (applicable if there only one segment) */
824    tr->tr_dataphys = segs[0].ds_addr;
825
826    /* correct command size for s/g list size */
827    tr->tr_command.generic.size += 2 * nsegments;
828
829    /*
830     * Due to the fact that parameter and I/O commands have the scatter/gather list in
831     * different places, we need to determine which sort of command this actually is
832     * before we can populate it correctly.
833     */
834    switch(cmd->generic.opcode) {
835    case TWE_OP_GET_PARAM:
836    case TWE_OP_SET_PARAM:
837	cmd->generic.sgl_offset = 2;
838	for (i = 0; i < nsegments; i++) {
839	    cmd->param.sgl[i].address = segs[i].ds_addr;
840	    cmd->param.sgl[i].length = segs[i].ds_len;
841	}
842	for (; i < TWE_MAX_SGL_LENGTH; i++) {		/* XXX necessary? */
843	    cmd->param.sgl[i].address = 0;
844	    cmd->param.sgl[i].length = 0;
845	}
846	break;
847    case TWE_OP_READ:
848    case TWE_OP_WRITE:
849	cmd->generic.sgl_offset = 3;
850	for (i = 0; i < nsegments; i++) {
851	    cmd->io.sgl[i].address = segs[i].ds_addr;
852	    cmd->io.sgl[i].length = segs[i].ds_len;
853	}
854	for (; i < TWE_MAX_SGL_LENGTH; i++) {		/* XXX necessary? */
855	    cmd->io.sgl[i].address = 0;
856	    cmd->io.sgl[i].length = 0;
857	}
858	break;
859    default:
860	/* no s/g list, nothing to do */
861    }
862}
863
864static void
865twe_setup_request_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
866{
867    struct twe_request	*tr = (struct twe_request *)arg;
868
869    debug_called(4);
870
871    /* command can't cross a page boundary */
872    tr->tr_cmdphys = segs[0].ds_addr;
873}
874
875void
876twe_map_request(struct twe_request *tr)
877{
878    struct twe_softc	*sc = tr->tr_sc;
879
880    debug_called(4);
881
882
883    /*
884     * Map the command into bus space.
885     */
886    bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_cmdmap, &tr->tr_command, sizeof(tr->tr_command),
887		    twe_setup_request_dmamap, tr, 0);
888    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_PREWRITE);
889
890    /*
891     * If the command involves data, map that too.
892     */
893    if (tr->tr_data != NULL) {
894
895	/*
896	 * Data must be 64-byte aligned; allocate a fixup buffer if it's not.
897	 */
898	if (((vm_offset_t)tr->tr_data % TWE_ALIGNMENT) != 0) {
899	    tr->tr_realdata = tr->tr_data;				/* save pointer to 'real' data */
900	    tr->tr_flags |= TWE_CMD_ALIGNBUF;
901	    tr->tr_data = malloc(tr->tr_length, TWE_MALLOC_CLASS, M_NOWAIT);	/* XXX check result here */
902	}
903
904	/*
905	 * Map the data buffer into bus space and build the s/g list.
906	 */
907	bus_dmamap_load(sc->twe_buffer_dmat, tr->tr_dmamap, tr->tr_data, tr->tr_length,
908			twe_setup_data_dmamap, tr, 0);
909	if (tr->tr_flags & TWE_CMD_DATAIN)
910	    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREREAD);
911	if (tr->tr_flags & TWE_CMD_DATAOUT) {
912	    /* if we're using an alignment buffer, and we're writing data, copy the real data out */
913	    if (tr->tr_flags & TWE_CMD_ALIGNBUF)
914		bcopy(tr->tr_realdata, tr->tr_data, tr->tr_length);
915	    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_PREWRITE);
916	}
917    }
918}
919
920void
921twe_unmap_request(struct twe_request *tr)
922{
923    struct twe_softc	*sc = tr->tr_sc;
924
925    debug_called(4);
926
927    /*
928     * Unmap the command from bus space.
929     */
930    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_cmdmap, BUS_DMASYNC_POSTWRITE);
931    bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_cmdmap);
932
933    /*
934     * If the command involved data, unmap that too.
935     */
936    if (tr->tr_data != NULL) {
937
938	if (tr->tr_flags & TWE_CMD_DATAIN) {
939	    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTREAD);
940	    /* if we're using an alignment buffer, and we're reading data, copy the real data in */
941	    if (tr->tr_flags & TWE_CMD_ALIGNBUF)
942		bcopy(tr->tr_data, tr->tr_realdata, tr->tr_length);
943	}
944	if (tr->tr_flags & TWE_CMD_DATAOUT)
945	    bus_dmamap_sync(sc->twe_buffer_dmat, tr->tr_dmamap, BUS_DMASYNC_POSTWRITE);
946
947	bus_dmamap_unload(sc->twe_buffer_dmat, tr->tr_dmamap);
948    }
949
950    /* free alignment buffer if it was used */
951    if (tr->tr_flags & TWE_CMD_ALIGNBUF) {
952	free(tr->tr_data, TWE_MALLOC_CLASS);
953	tr->tr_data = tr->tr_realdata;		/* restore 'real' data pointer */
954    }
955}
956
957#ifdef TWE_DEBUG
958/********************************************************************************
959 * Print current controller status, call from DDB.
960 */
961void
962twe_report(void)
963{
964    struct twe_softc	*sc;
965    int			i, s;
966
967    s = splbio();
968    for (i = 0; (sc = devclass_get_softc(twe_devclass, i)) != NULL; i++)
969	twe_print_controller(sc);
970    splx(s);
971}
972#endif
973