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