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