xref: /freebsd/sys/dev/aac/aac_disk.c (revision 6adf353a56a161443406b44a45d00c688ca7b857)
1 /*-
2  * Copyright (c) 2000 Michael Smith
3  * Copyright (c) 2001 Scott Long
4  * Copyright (c) 2000 BSDi
5  * Copyright (c) 2001 Adaptec, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  *	$FreeBSD$
30  */
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 
36 #include <dev/aac/aac_compat.h>
37 #include <sys/bus.h>
38 #include <sys/conf.h>
39 #include <sys/devicestat.h>
40 #include <sys/disk.h>
41 
42 #include <machine/bus.h>
43 #include <sys/rman.h>
44 
45 #include <dev/aac/aacreg.h>
46 #include <dev/aac/aac_ioctl.h>
47 #include <dev/aac/aacvar.h>
48 
49 /*
50  * Interface to parent.
51  */
52 static int aac_disk_probe(device_t dev);
53 static int aac_disk_attach(device_t dev);
54 static int aac_disk_detach(device_t dev);
55 
56 /*
57  * Interface to the device switch.
58  */
59 static	d_open_t	aac_disk_open;
60 static	d_close_t	aac_disk_close;
61 static	d_strategy_t	aac_disk_strategy;
62 
63 #define AAC_DISK_CDEV_MAJOR	151
64 
65 static struct cdevsw aac_disk_cdevsw = {
66     /* open */		aac_disk_open,
67     /* close */		aac_disk_close,
68     /* read */		physread,
69     /* write */		physwrite,
70     /* ioctl */		noioctl,
71     /* poll */		nopoll,
72     /* mmap */		nommap,
73     /* strategy */	aac_disk_strategy,
74     /* name */ 		"aacd",
75     /* maj */		AAC_DISK_CDEV_MAJOR,
76     /* dump */		nodump,
77     /* psize */ 	nopsize,
78     /* flags */		D_DISK,
79 };
80 
81 devclass_t		aac_disk_devclass;
82 static struct cdevsw	aac_disk_disk_cdevsw;
83 #ifdef FREEBSD_4
84 static int		disks_registered = 0;
85 #endif
86 
87 static device_method_t aac_disk_methods[] = {
88     DEVMETHOD(device_probe,	aac_disk_probe),
89     DEVMETHOD(device_attach,	aac_disk_attach),
90     DEVMETHOD(device_detach,	aac_disk_detach),
91     { 0, 0 }
92 };
93 
94 static driver_t aac_disk_driver = {
95     "aacd",
96     aac_disk_methods,
97     sizeof(struct aac_disk)
98 };
99 
100 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
101 
102 /******************************************************************************
103  * Handle open from generic layer.
104  *
105  * This is called by the diskslice code on first open in order to get the
106  * basic device geometry paramters.
107  */
108 static int
109 aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p)
110 {
111     struct aac_disk	*sc = (struct aac_disk *)dev->si_drv1;
112     struct disklabel	*label;
113 
114     debug_called(4);
115 
116     if (sc == NULL)
117 	return (ENXIO);
118 
119     /* check that the controller is up and running */
120     if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
121 	return(ENXIO);
122 
123     /* build synthetic label */
124     label = &sc->ad_disk.d_label;
125     bzero(label, sizeof(*label));
126     label->d_type = DTYPE_ESDI;
127     label->d_secsize    = AAC_BLOCK_SIZE;
128     label->d_nsectors   = sc->ad_sectors;
129     label->d_ntracks    = sc->ad_heads;
130     label->d_ncylinders = sc->ad_cylinders;
131     label->d_secpercyl  = sc->ad_sectors * sc->ad_heads;
132     label->d_secperunit = sc->ad_size;
133 
134     sc->ad_flags |= AAC_DISK_OPEN;
135     return (0);
136 }
137 
138 /******************************************************************************
139  * Handle last close of the disk device.
140  */
141 static int
142 aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p)
143 {
144     struct aac_disk	*sc = (struct aac_disk *)dev->si_drv1;
145 
146     debug_called(4);
147 
148     if (sc == NULL)
149 	return (ENXIO);
150 
151     sc->ad_flags &= ~AAC_DISK_OPEN;
152     return (0);
153 }
154 
155 /******************************************************************************
156  * Handle an I/O request.
157  */
158 static void
159 aac_disk_strategy(struct bio *bp)
160 {
161     struct aac_disk	*sc = (struct aac_disk *)bp->bio_dev->si_drv1;
162 
163     debug_called(4);
164 
165     /* bogus disk? */
166     if (sc == NULL) {
167 	bp->bio_flags |= BIO_ERROR;
168 	bp->bio_error = EINVAL;
169 	biodone(bp);
170 	return;
171     }
172 
173     /* perform accounting */
174     devstat_start_transaction(&sc->ad_stats);
175 
176     /* pass the bio to the controller - it can work out who we are */
177     aac_submit_bio(bp);
178     return;
179 }
180 
181 /******************************************************************************
182  * Handle completion of an I/O request.
183  */
184 void
185 aac_biodone(struct bio *bp)
186 {
187     struct aac_disk	*sc = (struct aac_disk *)bp->bio_dev->si_drv1;
188 
189     debug_called(4);
190 
191     devstat_end_transaction_bio(&sc->ad_stats, bp);
192     if (bp->bio_flags & BIO_ERROR)
193 	diskerr(bp, (char *)bp->bio_driver1, 0, &sc->ad_label);
194     biodone(bp);
195 }
196 
197 /******************************************************************************
198  * Stub only.
199  */
200 static int
201 aac_disk_probe(device_t dev)
202 {
203 
204     debug_called(4);
205 
206     return (0);
207 }
208 
209 /******************************************************************************
210  * Attach a unit to the controller.
211  */
212 static int
213 aac_disk_attach(device_t dev)
214 {
215     struct aac_disk	*sc = (struct aac_disk *)device_get_softc(dev);
216     int			sgspace;
217     int			maxsg;
218 
219     debug_called(4);
220 
221     /* initialise our softc */
222     sc->ad_controller =
223 	(struct aac_softc *)device_get_softc(device_get_parent(dev));
224     sc->ad_container = device_get_ivars(dev);
225     sc->ad_dev = dev;
226 
227     /*
228      * require that extended translation be enabled - other drivers read the
229      * disk!
230      */
231     sc->ad_size = sc->ad_container->co_mntobj.Capacity;
232     if (sc->ad_size >= (2 * 1024 * 1024)) {		/* 2GB */
233 	sc->ad_heads = 255;
234 	sc->ad_sectors = 63;
235     } else if (sc->ad_size >= (1 * 1024 * 1024)) {	/* 1GB */
236 	sc->ad_heads = 128;
237 	sc->ad_sectors = 32;
238     } else {
239 	sc->ad_heads = 64;
240 	sc->ad_sectors = 32;
241     }
242     sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
243 
244     device_printf(dev, "%uMB (%u sectors)\n",
245 		  sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size);
246 
247     devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
248 		      AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
249 		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
250 		      DEVSTAT_PRIORITY_ARRAY);
251 
252     /* attach a generic disk device to ourselves */
253     sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
254 			       &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
255     sc->ad_dev_t->si_drv1 = sc;
256 #ifdef FREEBSD_4
257     disks_registered++;
258 #endif
259 
260     /*
261      * We can calculate the maximum number of s/g entries based on the size of
262      * the FIB and the command structures packed within it.
263      */
264     sgspace = (sizeof(struct aac_fib) - sizeof(struct aac_fib_header) -
265 	       imax(sizeof(struct aac_blockwrite),
266 	       sizeof(struct aac_blockread)));
267     maxsg = (sgspace - sizeof(struct aac_sg_table)) /
268 	     sizeof(struct aac_sg_entry);
269 
270     /*
271      * set the maximum I/O size to the theoretical worst maximum allowed by the
272      * S/G list size
273      */
274     sc->ad_dev_t->si_iosize_max = (maxsg - 1) * PAGE_SIZE;
275 
276     return (0);
277 }
278 
279 /******************************************************************************
280  * Disconnect ourselves from the system.
281  */
282 static int
283 aac_disk_detach(device_t dev)
284 {
285     struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
286 
287     debug_called(4);
288 
289     if (sc->ad_flags & AAC_DISK_OPEN)
290 	return(EBUSY);
291 
292     devstat_remove_entry(&sc->ad_stats);
293 #ifdef FREEBSD_4
294     if (--disks_registered == 0)
295 	cdevsw_remove(&aac_disk_disk_cdevsw);
296 #else
297     disk_destroy(sc->ad_dev_t);
298 #endif
299 
300     return(0);
301 }
302 
303