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