xref: /freebsd/sys/dev/aac/aac_disk.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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$
28  */
29 
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 
34 #include <dev/aac/aac_compat.h>
35 #include <sys/bus.h>
36 #include <sys/conf.h>
37 #include <sys/devicestat.h>
38 #include <sys/disk.h>
39 
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 
43 #include <dev/aac/aacreg.h>
44 #include <dev/aac/aacvar.h>
45 
46 /*
47  * Interface to parent.
48  */
49 static int aac_disk_probe(device_t dev);
50 static int aac_disk_attach(device_t dev);
51 static int aac_disk_detach(device_t dev);
52 
53 /*
54  * Interface to the device switch.
55  */
56 static	d_open_t	aac_disk_open;
57 static	d_close_t	aac_disk_close;
58 static	d_strategy_t	aac_disk_strategy;
59 
60 #define AAC_DISK_CDEV_MAJOR	151
61 
62 static struct cdevsw aac_disk_cdevsw = {
63     /* open */		aac_disk_open,
64     /* close */		aac_disk_close,
65     /* read */		physread,
66     /* write */		physwrite,
67     /* ioctl */		noioctl,
68     /* poll */		nopoll,
69     /* mmap */		nommap,
70     /* strategy */	aac_disk_strategy,
71     /* name */ 		"aacd",
72     /* maj */		AAC_DISK_CDEV_MAJOR,
73     /* dump */		nodump,
74     /* psize */ 	nopsize,
75     /* flags */		D_DISK,
76     /* bmaj */		-1
77 };
78 
79 devclass_t		aac_disk_devclass;
80 static struct cdevsw	aac_disk_disk_cdevsw;
81 #ifdef FREEBSD_4
82 static int		disks_registered = 0;
83 #endif
84 
85 static device_method_t aac_disk_methods[] = {
86     DEVMETHOD(device_probe,	aac_disk_probe),
87     DEVMETHOD(device_attach,	aac_disk_attach),
88     DEVMETHOD(device_detach,	aac_disk_detach),
89     { 0, 0 }
90 };
91 
92 static driver_t aac_disk_driver = {
93     "aacd",
94     aac_disk_methods,
95     sizeof(struct aac_disk)
96 };
97 
98 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
99 
100 /********************************************************************************
101  * Handle open from generic layer.
102  *
103  * This is called by the diskslice code on first open in order to get the
104  * basic device geometry paramters.
105  */
106 static int
107 aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p)
108 {
109     struct aac_disk	*sc = (struct aac_disk *)dev->si_drv1;
110     struct disklabel	*label;
111 
112     debug_called(4);
113 
114     if (sc == NULL)
115 	return (ENXIO);
116 
117     /* check that the controller is up and running */
118     if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
119 	return(ENXIO);
120 
121     /* build synthetic label */
122     label = &sc->ad_disk.d_label;
123     bzero(label, sizeof(*label));
124     label->d_type = DTYPE_ESDI;
125     label->d_secsize    = AAC_BLOCK_SIZE;
126     label->d_nsectors   = sc->ad_sectors;
127     label->d_ntracks    = sc->ad_heads;
128     label->d_ncylinders = sc->ad_cylinders;
129     label->d_secpercyl  = sc->ad_sectors * sc->ad_heads;
130     label->d_secperunit = sc->ad_size;
131 
132     sc->ad_flags |= AAC_DISK_OPEN;
133     return (0);
134 }
135 
136 /********************************************************************************
137  * Handle last close of the disk device.
138  */
139 static int
140 aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p)
141 {
142     struct aac_disk	*sc = (struct aac_disk *)dev->si_drv1;
143 
144     debug_called(4);
145 
146     if (sc == NULL)
147 	return (ENXIO);
148 
149     sc->ad_flags &= ~AAC_DISK_OPEN;
150     return (0);
151 }
152 
153 /********************************************************************************
154  * Handle an I/O request.
155  */
156 static void
157 aac_disk_strategy(struct bio *bp)
158 {
159     struct aac_disk	*sc = (struct aac_disk *)bp->bio_dev->si_drv1;
160 
161     debug_called(4);
162 
163     /* bogus disk? */
164     if (sc == NULL) {
165 	bp->bio_flags |= BIO_ERROR;
166 	bp->bio_error = EINVAL;
167 	biodone(bp);
168 	return;
169     }
170 
171     /* do-nothing operation? */
172     if (bp->bio_bcount == 0) {
173 	bp->bio_resid = bp->bio_bcount;
174 	biodone(bp);
175 	return;
176     }
177 
178     /* perform accounting */
179     devstat_start_transaction(&sc->ad_stats);
180 
181     /* pass the bio to the controller - it can work out who we are */
182     aac_submit_bio(bp);
183     return;
184 }
185 
186 /********************************************************************************
187  * Handle completion of an I/O request.
188  */
189 void
190 aac_complete_bio(struct bio *bp)
191 {
192     struct aac_disk	*sc = (struct aac_disk *)bp->bio_dev->si_drv1;
193 
194     debug_called(4);
195 
196     devstat_end_transaction_bio(&sc->ad_stats, bp);
197     biodone(bp);
198 }
199 
200 /********************************************************************************
201  * Stub only.
202  */
203 static int
204 aac_disk_probe(device_t dev)
205 {
206 
207     debug_called(4);
208 
209     return (0);
210 }
211 
212 /********************************************************************************
213  * Attach a unit to the controller.
214  */
215 static int
216 aac_disk_attach(device_t dev)
217 {
218     struct aac_disk	*sc = (struct aac_disk *)device_get_softc(dev);
219     int			sgspace;
220     int			maxsg;
221 
222     debug_called(4);
223 
224     /* initialise our softc */
225     sc->ad_controller = (struct aac_softc *)device_get_softc(device_get_parent(dev));
226     sc->ad_container = device_get_ivars(dev);
227     sc->ad_dev = dev;
228 
229     /* require that extended translation be enabled  XXX document! */
230     sc->ad_size = sc->ad_container->co_mntobj.Capacity;
231     if (sc->ad_size >= (2 * 1024 * 1024)) {		/* 2GB */
232 	sc->ad_heads = 255;
233 	sc->ad_sectors = 63;
234     } else if (sc->ad_size >= (2 * 1024 * 1024)) {	/* 1GB */
235 	sc->ad_heads = 128;
236 	sc->ad_sectors = 32;
237     } else {
238 	sc->ad_heads = 64;
239 	sc->ad_sectors = 32;
240     }
241     sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
242 
243     device_printf(dev, "%uMB (%u sectors)\n",
244 		  sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size);
245 
246     devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), AAC_BLOCK_SIZE,
247 		      DEVSTAT_NO_ORDERED_TAGS,
248 		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
249 		      DEVSTAT_PRIORITY_ARRAY);
250 
251     /* attach a generic disk device to ourselves */
252     sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
253     sc->ad_dev_t->si_drv1 = sc;
254 #ifdef FREEBSD_4
255     disks_registered++;
256 #endif
257 
258     /*
259      * We can calculate the maximum number of s/g entries based on the size of the
260      * FIB and the command structures packed within it.
261      */
262     sgspace = (sizeof(struct aac_fib) - sizeof(struct aac_fib_header) -
263 	       imax(sizeof(struct aac_blockwrite), sizeof(struct aac_blockread)));
264     maxsg = (sgspace - sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_entry);
265 
266     /* set the maximum I/O size to the theoretical worst maximum allowed by the S/G list size */
267     sc->ad_dev_t->si_iosize_max = (maxsg - 1) * PAGE_SIZE;
268 
269     return (0);
270 }
271 
272 /********************************************************************************
273  * Disconnect ourselves from the system.
274  */
275 static int
276 aac_disk_detach(device_t dev)
277 {
278     struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
279 
280     debug_called(4);
281 
282     if (sc->ad_flags & AAC_DISK_OPEN)
283 	return(EBUSY);
284 
285     devstat_remove_entry(&sc->ad_stats);
286 #ifdef FREEBSD_4
287     if (--disks_registered == 0)
288 	cdevsw_remove(&aac_disk_disk_cdevsw);
289 #else
290     disk_destroy(sc->ad_dev_t);
291 #endif
292 
293     return(0);
294 }
295 
296