Deleted Added
full compact
aac_disk.c (82830) aac_disk.c (83114)
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

--- 12 unchanged lines hidden (view full) ---

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 *
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

--- 12 unchanged lines hidden (view full) ---

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: head/sys/dev/aac/aac_disk.c 82830 2001-09-02 23:16:40Z scottl $
29 * $FreeBSD: head/sys/dev/aac/aac_disk.c 83114 2001-09-05 20:43:02Z scottl $
30 */
31
32#include "opt_aac.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/sysctl.h>

--- 28 unchanged lines hidden (view full) ---

66static d_open_t aac_disk_open;
67static d_close_t aac_disk_close;
68static d_strategy_t aac_disk_strategy;
69static d_dump_t aac_disk_dump;
70
71#define AAC_DISK_CDEV_MAJOR 151
72
73static struct cdevsw aac_disk_cdevsw = {
30 */
31
32#include "opt_aac.h"
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/sysctl.h>

--- 28 unchanged lines hidden (view full) ---

66static d_open_t aac_disk_open;
67static d_close_t aac_disk_close;
68static d_strategy_t aac_disk_strategy;
69static d_dump_t aac_disk_dump;
70
71#define AAC_DISK_CDEV_MAJOR 151
72
73static struct cdevsw aac_disk_cdevsw = {
74 /* open */ aac_disk_open,
75 /* close */ aac_disk_close,
76 /* read */ physread,
77 /* write */ physwrite,
78 /* ioctl */ noioctl,
79 /* poll */ nopoll,
80 /* mmap */ nommap,
81 /* strategy */ aac_disk_strategy,
82 /* name */ "aacd",
83 /* maj */ AAC_DISK_CDEV_MAJOR,
84 /* dump */ aac_disk_dump,
85 /* psize */ nopsize,
86 /* flags */ D_DISK,
74 /* open */ aac_disk_open,
75 /* close */ aac_disk_close,
76 /* read */ physread,
77 /* write */ physwrite,
78 /* ioctl */ noioctl,
79 /* poll */ nopoll,
80 /* mmap */ nommap,
81 /* strategy */ aac_disk_strategy,
82 /* name */ "aacd",
83 /* maj */ AAC_DISK_CDEV_MAJOR,
84 /* dump */ aac_disk_dump,
85 /* psize */ nopsize,
86 /* flags */ D_DISK,
87#if __FreeBSD_version < 500005
87#if __FreeBSD_version < 500005
88 /* bmaj */ -1
88 /* bmaj */ -1
89#endif
90};
91
92devclass_t aac_disk_devclass;
93static struct cdevsw aac_disk_disk_cdevsw;
94#ifdef FREEBSD_4
95static int disks_registered = 0;
96#endif
97
98static device_method_t aac_disk_methods[] = {
89#endif
90};
91
92devclass_t aac_disk_devclass;
93static struct cdevsw aac_disk_disk_cdevsw;
94#ifdef FREEBSD_4
95static int disks_registered = 0;
96#endif
97
98static device_method_t aac_disk_methods[] = {
99 DEVMETHOD(device_probe, aac_disk_probe),
100 DEVMETHOD(device_attach, aac_disk_attach),
101 DEVMETHOD(device_detach, aac_disk_detach),
102 { 0, 0 }
99 DEVMETHOD(device_probe, aac_disk_probe),
100 DEVMETHOD(device_attach, aac_disk_attach),
101 DEVMETHOD(device_detach, aac_disk_detach),
102 { 0, 0 }
103};
104
105static driver_t aac_disk_driver = {
103};
104
105static driver_t aac_disk_driver = {
106 "aacd",
107 aac_disk_methods,
108 sizeof(struct aac_disk)
106 "aacd",
107 aac_disk_methods,
108 sizeof(struct aac_disk)
109};
110
111DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
112
113/* sysctl tunables */
114static unsigned int aac_iosize_max = 65536; /* due to limits of the card */
115TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
116
117SYSCTL_DECL(_hw_aac);
118SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
119 "Max I/O size per transfer to an array");
120
121#define AAC_MAXIO 65536
122
109};
110
111DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
112
113/* sysctl tunables */
114static unsigned int aac_iosize_max = 65536; /* due to limits of the card */
115TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
116
117SYSCTL_DECL(_hw_aac);
118SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
119 "Max I/O size per transfer to an array");
120
121#define AAC_MAXIO 65536
122
123/******************************************************************************
123/*
124 * Handle open from generic layer.
125 *
126 * This is called by the diskslice code on first open in order to get the
127 * basic device geometry paramters.
128 */
129static int
130aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p)
131{
124 * Handle open from generic layer.
125 *
126 * This is called by the diskslice code on first open in order to get the
127 * basic device geometry paramters.
128 */
129static int
130aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p)
131{
132 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1;
133 struct disklabel *label;
132 struct aac_disk *sc;
133 struct disklabel *label;
134
134
135 debug_called(4);
135 debug_called(4);
136
137 sc = (struct aac_disk *)dev->si_drv1;
136
138
137 if (sc == NULL)
138 return (ENXIO);
139 if (sc == NULL)
140 return (ENXIO);
139
141
140 /* check that the controller is up and running */
141 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
142 return(ENXIO);
142 /* check that the controller is up and running */
143 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
144 return(ENXIO);
143
145
144 /* build synthetic label */
145 label = &sc->ad_disk.d_label;
146 bzero(label, sizeof(*label));
147 label->d_type = DTYPE_ESDI;
148 label->d_secsize = AAC_BLOCK_SIZE;
149 label->d_nsectors = sc->ad_sectors;
150 label->d_ntracks = sc->ad_heads;
151 label->d_ncylinders = sc->ad_cylinders;
152 label->d_secpercyl = sc->ad_sectors * sc->ad_heads;
153 label->d_secperunit = sc->ad_size;
146 /* build synthetic label */
147 label = &sc->ad_disk.d_label;
148 bzero(label, sizeof(*label));
149 label->d_type = DTYPE_ESDI;
150 label->d_secsize = AAC_BLOCK_SIZE;
151 label->d_nsectors = sc->ad_sectors;
152 label->d_ntracks = sc->ad_heads;
153 label->d_ncylinders = sc->ad_cylinders;
154 label->d_secpercyl = sc->ad_sectors * sc->ad_heads;
155 label->d_secperunit = sc->ad_size;
154
156
155 sc->ad_flags |= AAC_DISK_OPEN;
156 return (0);
157 sc->ad_flags |= AAC_DISK_OPEN;
158 return (0);
157}
158
159}
160
159/******************************************************************************
161/*
160 * Handle last close of the disk device.
161 */
162static int
163aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p)
164{
162 * Handle last close of the disk device.
163 */
164static int
165aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p)
166{
165 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1;
167 struct aac_disk *sc;
166
168
167 debug_called(4);
169 debug_called(4);
170
171 sc = (struct aac_disk *)dev->si_drv1;
168
172
169 if (sc == NULL)
170 return (ENXIO);
173 if (sc == NULL)
174 return (ENXIO);
171
175
172 sc->ad_flags &= ~AAC_DISK_OPEN;
173 return (0);
176 sc->ad_flags &= ~AAC_DISK_OPEN;
177 return (0);
174}
175
178}
179
176/******************************************************************************
180/*
177 * Handle an I/O request.
178 */
179static void
180aac_disk_strategy(struct bio *bp)
181{
181 * Handle an I/O request.
182 */
183static void
184aac_disk_strategy(struct bio *bp)
185{
182 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1;
186 struct aac_disk *sc;
183
187
184 debug_called(4);
188 debug_called(4);
185
189
186 /* bogus disk? */
187 if (sc == NULL) {
188 bp->bio_flags |= BIO_ERROR;
189 bp->bio_error = EINVAL;
190 biodone(bp);
191 return;
192 }
190 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
193
191
194 /* do-nothing operation? */
195 if (bp->bio_bcount == 0) {
196 bp->bio_resid = bp->bio_bcount;
197 biodone(bp);
198 return;
199 }
192 /* bogus disk? */
193 if (sc == NULL) {
194 bp->bio_flags |= BIO_ERROR;
195 bp->bio_error = EINVAL;
196 biodone(bp);
197 return;
198 }
200
199
201 /* perform accounting */
202 devstat_start_transaction(&sc->ad_stats);
200 /* do-nothing operation? */
201 if (bp->bio_bcount == 0) {
202 bp->bio_resid = bp->bio_bcount;
203 biodone(bp);
204 return;
205 }
203
206
204 /* pass the bio to the controller - it can work out who we are */
205 aac_submit_bio(bp);
206 return;
207 /* perform accounting */
208 devstat_start_transaction(&sc->ad_stats);
209
210 /* pass the bio to the controller - it can work out who we are */
211 aac_submit_bio(bp);
212 return;
207}
208
213}
214
209/******************************************************************************
215/*
210 * Dump memory out to an array
211 *
212 * This queues blocks of memory of size AAC_MAXIO to the controller and waits
213 * for the controller to complete the requests.
214 */
215static int
216aac_disk_dump(dev_t dev)
217{
216 * Dump memory out to an array
217 *
218 * This queues blocks of memory of size AAC_MAXIO to the controller and waits
219 * for the controller to complete the requests.
220 */
221static int
222aac_disk_dump(dev_t dev)
223{
218 struct aac_disk *ad = dev->si_drv1;
219 struct aac_softc *sc;
220 vm_offset_t addr = 0;
221 long blkcnt;
222 unsigned int count, blkno, secsize;
223 int dumppages = AAC_MAXIO / PAGE_SIZE;
224 int i, error;
224 struct aac_disk *ad;
225 struct aac_softc *sc;
226 vm_offset_t addr;
227 long blkcnt;
228 unsigned int count, blkno, secsize;
229 int dumppages;
230 int i, error;
225
231
226 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
227 return (error);
232 ad = dev->si_drv1;
233 addr = 0;
234 dumppages = AAC_MAXIO / PAGE_SIZE;
228
235
229 if (ad == NULL)
230 return (ENXIO);
236 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
237 return (error);
231
238
232 sc= ad->ad_controller;
239 if (ad == NULL)
240 return (ENXIO);
233
241
234 blkcnt = howmany(PAGE_SIZE, secsize);
242 sc= ad->ad_controller;
235
243
236 while (count > 0) {
237 caddr_t va = NULL;
244 blkcnt = howmany(PAGE_SIZE, secsize);
238
245
239 if ((count / blkcnt) < dumppages)
240 dumppages = count / blkcnt;
246 while (count > 0) {
247 caddr_t va = NULL;
241
248
242 for (i = 0; i < dumppages; ++i) {
243 vm_offset_t a = addr + (i * PAGE_SIZE);
244 if (is_physical_memory(a)) {
245 va = pmap_kenter_temporary(trunc_page(a), i);
246 } else {
247 va = pmap_kenter_temporary(trunc_page(0), i);
248 }
249 }
249 if ((count / blkcnt) < dumppages)
250 dumppages = count / blkcnt;
250
251
252 for (i = 0; i < dumppages; ++i) {
253 vm_offset_t a = addr + (i * PAGE_SIZE);
254 if (is_physical_memory(a)) {
255 va = pmap_kenter_temporary(trunc_page(a), i);
256 } else {
257 va = pmap_kenter_temporary(trunc_page(0), i);
258 }
259 }
260
251retry:
261retry:
252 /*
253 * Queue the block to the controller. If the queue is full, EBUSY
254 * will be returned.
255 */
256 error = aac_dump_enqueue(ad, blkno, va, dumppages);
257 if (error && (error != EBUSY))
258 return (error);
262 /*
263 * Queue the block to the controller. If the queue is full,
264 * EBUSY will be returned.
265 */
266 error = aac_dump_enqueue(ad, blkno, va, dumppages);
267 if (error && (error != EBUSY))
268 return (error);
259
269
260 if (!error) {
261 if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0)
262 return (EINTR);
270 if (!error) {
271 if (dumpstatus(addr, (long)(count * DEV_BSIZE)) < 0)
272 return (EINTR);
263
273
264 blkno += blkcnt * dumppages;
265 count -= blkcnt * dumppages;
266 addr += PAGE_SIZE * dumppages;
267 if (count > 0)
268 continue;
269 }
274 blkno += blkcnt * dumppages;
275 count -= blkcnt * dumppages;
276 addr += PAGE_SIZE * dumppages;
277 if (count > 0)
278 continue;
279 }
270
280
271 /*
272 * Either the queue was full on the last attemp, or we have no more
273 * data to dump. Let the queue drain out and retry the block if
274 * the queue was full.
275 */
276 aac_dump_complete(sc);
281 /*
282 * Either the queue was full on the last attemp, or we have no
283 * more data to dump. Let the queue drain out and retry the
284 * block if the queue was full.
285 */
286 aac_dump_complete(sc);
277
287
278 if (error == EBUSY)
279 goto retry;
280 }
288 if (error == EBUSY)
289 goto retry;
290 }
281
291
282 return (0);
292 return (0);
283}
284
293}
294
285/******************************************************************************
295/*
286 * Handle completion of an I/O request.
287 */
288void
289aac_biodone(struct bio *bp)
290{
296 * Handle completion of an I/O request.
297 */
298void
299aac_biodone(struct bio *bp)
300{
291 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1;
301 struct aac_disk *sc;
302 int blkno;
292
303
293 debug_called(4);
304 debug_called(4);
294
305
295 devstat_end_transaction_bio(&sc->ad_stats, bp);
296 if (bp->bio_flags & BIO_ERROR) {
297 /*
298 * XXX For some reason, the disklabel seems to get zero'd out. This
299 * will cause diskerr to panic unless we pass in -1 as the blkno.
300 */
301 int blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
306 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
307
308 devstat_end_transaction_bio(&sc->ad_stats, bp);
309 if (bp->bio_flags & BIO_ERROR) {
310 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
302#if __FreeBSD_version > 500005
311#if __FreeBSD_version > 500005
303 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
312 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
304#else
313#else
305 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
314 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
306#endif
315#endif
307 }
308 biodone(bp);
316 }
317 biodone(bp);
309}
310
318}
319
311/******************************************************************************
320/*
312 * Stub only.
313 */
314static int
315aac_disk_probe(device_t dev)
316{
317
321 * Stub only.
322 */
323static int
324aac_disk_probe(device_t dev)
325{
326
318 debug_called(2);
327 debug_called(2);
319
328
320 return (0);
329 return (0);
321}
322
330}
331
323/******************************************************************************
332/*
324 * Attach a unit to the controller.
325 */
326static int
327aac_disk_attach(device_t dev)
328{
333 * Attach a unit to the controller.
334 */
335static int
336aac_disk_attach(device_t dev)
337{
329 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
330
331 debug_called(1);
338 struct aac_disk *sc;
339
340 debug_called(1);
332
341
333 /* initialise our softc */
334 sc->ad_controller =
335 (struct aac_softc *)device_get_softc(device_get_parent(dev));
336 sc->ad_container = device_get_ivars(dev);
337 sc->ad_dev = dev;
342 sc = (struct aac_disk *)device_get_softc(dev);
338
343
339 /*
340 * require that extended translation be enabled - other drivers read the
341 * disk!
342 */
343 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
344 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
345 sc->ad_heads = 255;
346 sc->ad_sectors = 63;
347 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
348 sc->ad_heads = 128;
349 sc->ad_sectors = 32;
350 } else {
351 sc->ad_heads = 64;
352 sc->ad_sectors = 32;
353 }
354 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
344 /* initialise our softc */
345 sc->ad_controller =
346 (struct aac_softc *)device_get_softc(device_get_parent(dev));
347 sc->ad_container = device_get_ivars(dev);
348 sc->ad_dev = dev;
355
349
356 device_printf(dev, "%uMB (%u sectors)\n",
357 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size);
350 /*
351 * require that extended translation be enabled - other drivers read the
352 * disk!
353 */
354 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
355 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
356 sc->ad_heads = 255;
357 sc->ad_sectors = 63;
358 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
359 sc->ad_heads = 128;
360 sc->ad_sectors = 32;
361 } else {
362 sc->ad_heads = 64;
363 sc->ad_sectors = 32;
364 }
365 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
358
366
359 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
360 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
361 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
362 DEVSTAT_PRIORITY_ARRAY);
367 device_printf(dev, "%uMB (%u sectors)\n",
368 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
369 sc->ad_size);
363
370
364 /* attach a generic disk device to ourselves */
365 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
366 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
367 sc->ad_dev_t->si_drv1 = sc;
371 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
372 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
373 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
374 DEVSTAT_PRIORITY_ARRAY);
375
376 /* attach a generic disk device to ourselves */
377 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
378 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
379 sc->ad_dev_t->si_drv1 = sc;
368#ifdef FREEBSD_4
380#ifdef FREEBSD_4
369 disks_registered++;
381 disks_registered++;
370#endif
371
382#endif
383
372 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
373 sc->unit = device_get_unit(dev);
384 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
385 sc->unit = device_get_unit(dev);
374
386
375 return (0);
387 return (0);
376}
377
388}
389
378/******************************************************************************
390/*
379 * Disconnect ourselves from the system.
380 */
381static int
382aac_disk_detach(device_t dev)
383{
391 * Disconnect ourselves from the system.
392 */
393static int
394aac_disk_detach(device_t dev)
395{
384 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev);
396 struct aac_disk *sc;
385
397
386 debug_called(2);
398 debug_called(2);
387
399
388 if (sc->ad_flags & AAC_DISK_OPEN)
389 return(EBUSY);
400 sc = (struct aac_disk *)device_get_softc(dev);
390
401
391 devstat_remove_entry(&sc->ad_stats);
392 disk_destroy(sc->ad_dev_t);
402 if (sc->ad_flags & AAC_DISK_OPEN)
403 return(EBUSY);
404
405 devstat_remove_entry(&sc->ad_stats);
406 disk_destroy(sc->ad_dev_t);
393#ifdef FREEBSD_4
407#ifdef FREEBSD_4
394 if (--disks_registered == 0)
395 cdevsw_remove(&aac_disk_cdevsw);
408 if (--disks_registered == 0)
409 cdevsw_remove(&aac_disk_cdevsw);
396#endif
397
410#endif
411
398 return(0);
412 return(0);
399}
413}
400