Deleted Added
full compact
aac_disk.c (103675) aac_disk.c (103714)
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 *
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: head/sys/dev/aac/aac_disk.c 103675 2002-09-20 12:52:03Z phk $
29 * $FreeBSD: head/sys/dev/aac/aac_disk.c 103714 2002-09-20 19:36:05Z phk $
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>
38
39#include <dev/aac/aac_compat.h>
40#include <sys/bus.h>
41#include <sys/conf.h>
42#include <sys/devicestat.h>
43#include <sys/disk.h>
44
45#include <vm/vm.h>
46#include <vm/pmap.h>
47
48#include <machine/md_var.h>
49#include <machine/bus.h>
50#include <sys/rman.h>
51
52#include <dev/aac/aacreg.h>
53#include <dev/aac/aac_ioctl.h>
54#include <dev/aac/aacvar.h>
55
56/*
57 * Interface to parent.
58 */
59static int aac_disk_probe(device_t dev);
60static int aac_disk_attach(device_t dev);
61static int aac_disk_detach(device_t dev);
62
63/*
64 * Interface to the device switch.
65 */
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,
87#if __FreeBSD_version < 500005
88 /* bmaj */ -1
89#endif
90};
91
92static devclass_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 }
103};
104
105static driver_t aac_disk_driver = {
106 "aacd",
107 aac_disk_methods,
108 sizeof(struct aac_disk)
109};
110
111#define AAC_MAXIO 65536
112
113DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
114
115/* sysctl tunables */
116static unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */
117TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
118
119SYSCTL_DECL(_hw_aac);
120SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
121 "Max I/O size per transfer to an array");
122
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, d_thread_t *td)
131{
132 struct aac_disk *sc;
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>
38
39#include <dev/aac/aac_compat.h>
40#include <sys/bus.h>
41#include <sys/conf.h>
42#include <sys/devicestat.h>
43#include <sys/disk.h>
44
45#include <vm/vm.h>
46#include <vm/pmap.h>
47
48#include <machine/md_var.h>
49#include <machine/bus.h>
50#include <sys/rman.h>
51
52#include <dev/aac/aacreg.h>
53#include <dev/aac/aac_ioctl.h>
54#include <dev/aac/aacvar.h>
55
56/*
57 * Interface to parent.
58 */
59static int aac_disk_probe(device_t dev);
60static int aac_disk_attach(device_t dev);
61static int aac_disk_detach(device_t dev);
62
63/*
64 * Interface to the device switch.
65 */
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,
87#if __FreeBSD_version < 500005
88 /* bmaj */ -1
89#endif
90};
91
92static devclass_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 }
103};
104
105static driver_t aac_disk_driver = {
106 "aacd",
107 aac_disk_methods,
108 sizeof(struct aac_disk)
109};
110
111#define AAC_MAXIO 65536
112
113DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
114
115/* sysctl tunables */
116static unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */
117TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max);
118
119SYSCTL_DECL(_hw_aac);
120SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0,
121 "Max I/O size per transfer to an array");
122
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, d_thread_t *td)
131{
132 struct aac_disk *sc;
133 struct disklabel *label;
134
135 debug_called(4);
136
137 sc = (struct aac_disk *)dev->si_drv1;
138
139 if (sc == NULL)
140 return (ENXIO);
141
142 /* check that the controller is up and running */
143 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
144 return(ENXIO);
145
133
134 debug_called(4);
135
136 sc = (struct aac_disk *)dev->si_drv1;
137
138 if (sc == NULL)
139 return (ENXIO);
140
141 /* check that the controller is up and running */
142 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND)
143 return(ENXIO);
144
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;
145 sc->ad_disk.d_sectorsize = AAC_BLOCK_SIZE;
146 sc->ad_disk.d_mediasize = (off_t)sc->ad_size * AAC_BLOCK_SIZE;
147 sc->ad_disk.d_fwsectors = sc->ad_sectors;
148 sc->ad_disk.d_fwheads = sc->ad_heads;
156
157 sc->ad_flags |= AAC_DISK_OPEN;
158 return (0);
159}
160
161/*
162 * Handle last close of the disk device.
163 */
164static int
165aac_disk_close(dev_t dev, int flags, int fmt, d_thread_t *td)
166{
167 struct aac_disk *sc;
168
169 debug_called(4);
170
171 sc = (struct aac_disk *)dev->si_drv1;
172
173 if (sc == NULL)
174 return (ENXIO);
175
176 sc->ad_flags &= ~AAC_DISK_OPEN;
177 return (0);
178}
179
180/*
181 * Handle an I/O request.
182 */
183static void
184aac_disk_strategy(struct bio *bp)
185{
186 struct aac_disk *sc;
187
188 debug_called(4);
189
190 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
191
192 /* bogus disk? */
193 if (sc == NULL) {
194 bp->bio_flags |= BIO_ERROR;
195 bp->bio_error = EINVAL;
196 biodone(bp);
197 return;
198 }
199
200 /* do-nothing operation? */
201 if (bp->bio_bcount == 0) {
202 bp->bio_resid = bp->bio_bcount;
203 biodone(bp);
204 return;
205 }
206
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;
213}
214
215/*
216 * Map the S/G elements for doing a dump.
217 */
218static void
219aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
220{
221 struct aac_fib *fib;
222 struct aac_blockwrite *bw;
223 struct aac_sg_table *sg;
224 int i;
225
226 fib = (struct aac_fib *)arg;
227 bw = (struct aac_blockwrite *)&fib->data[0];
228 sg = &bw->SgMap;
229
230 if (sg != NULL) {
231 sg->SgCount = nsegs;
232 for (i = 0; i < nsegs; i++) {
233 sg->SgEntry[i].SgAddress = segs[i].ds_addr;
234 sg->SgEntry[i].SgByteCount = segs[i].ds_len;
235 }
236 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
237 }
238}
239
240/*
241 * Dump memory out to an array
242 *
243 * Send out one command at a time with up to AAC_MAXIO of data.
244 */
245static int
246aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length)
247{
248 struct aac_disk *ad;
249 struct aac_softc *sc;
250 struct aac_fib *fib;
251 struct aac_blockwrite *bw;
252 size_t len;
253 int size;
254 static bus_dmamap_t dump_datamap;
255 static int first = 0;
256
257 ad = dev->si_drv1;
258
259 if (ad == NULL)
260 return (EINVAL);
261
262 sc= ad->ad_controller;
263
264 if (!first) {
265 first = 1;
266 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
267 printf("bus_dmamap_create failed\n");
268 return (ENOMEM);
269 }
270 }
271
272 aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
273 bw = (struct aac_blockwrite *)&fib->data[0];
274
275 while (length > 0) {
276 len = (length > AAC_MAXIO) ? AAC_MAXIO : length;
277 bw->Command = VM_CtBlockWrite;
278 bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
279 bw->BlockNumber = offset / AAC_BLOCK_SIZE;
280 bw->ByteCount = len;
281 bw->Stable = CUNSTABLE;
282 bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
283 len, aac_dump_map_sg, fib, 0);
284 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
285 BUS_DMASYNC_PREWRITE);
286
287 /* fib->Header.Size is set in aac_dump_map_sg */
288 size = fib->Header.Size + sizeof(struct aac_blockwrite);
289
290 if (aac_sync_fib(sc, ContainerCommand, 0, fib, size)) {
291 printf("Error dumping block 0x%x\n", physical);
292 return (EIO);
293 }
294 length -= len;
295 offset += len;
296 }
297
298 return (0);
299}
300
301/*
302 * Handle completion of an I/O request.
303 */
304void
305aac_biodone(struct bio *bp)
306{
307 struct aac_disk *sc;
308
309 debug_called(4);
310
311 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
312
313 devstat_end_transaction_bio(&sc->ad_stats, bp);
314 if (bp->bio_flags & BIO_ERROR) {
315#if __FreeBSD_version > 500039
316 disk_err(bp, "hard error", -1, 1);
317#elif __FreeBSD_version > 500005
318 int blkno;
319 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
320 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
321#else
322 int blkno;
323 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
324 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
325#endif
326 }
327 biodone(bp);
328}
329
330/*
331 * Stub only.
332 */
333static int
334aac_disk_probe(device_t dev)
335{
336
337 debug_called(2);
338
339 return (0);
340}
341
342/*
343 * Attach a unit to the controller.
344 */
345static int
346aac_disk_attach(device_t dev)
347{
348 struct aac_disk *sc;
349
350 debug_called(1);
351
352 sc = (struct aac_disk *)device_get_softc(dev);
353
354 /* initialise our softc */
355 sc->ad_controller =
356 (struct aac_softc *)device_get_softc(device_get_parent(dev));
357 sc->ad_container = device_get_ivars(dev);
358 sc->ad_dev = dev;
359
360 /*
361 * require that extended translation be enabled - other drivers read the
362 * disk!
363 */
364 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
365 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
366 sc->ad_heads = 255;
367 sc->ad_sectors = 63;
368 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
369 sc->ad_heads = 128;
370 sc->ad_sectors = 32;
371 } else {
372 sc->ad_heads = 64;
373 sc->ad_sectors = 32;
374 }
375 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
376
377 device_printf(dev, "%uMB (%u sectors)\n",
378 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
379 sc->ad_size);
380
381 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
382 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
383 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
384 DEVSTAT_PRIORITY_ARRAY);
385
386 /* attach a generic disk device to ourselves */
387 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
388 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
389 sc->ad_dev_t->si_drv1 = sc;
390#ifdef FREEBSD_4
391 disks_registered++;
392#endif
393
394 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
395 sc->unit = device_get_unit(dev);
396
397 return (0);
398}
399
400/*
401 * Disconnect ourselves from the system.
402 */
403static int
404aac_disk_detach(device_t dev)
405{
406 struct aac_disk *sc;
407
408 debug_called(2);
409
410 sc = (struct aac_disk *)device_get_softc(dev);
411
412 if (sc->ad_flags & AAC_DISK_OPEN)
413 return(EBUSY);
414
415 devstat_remove_entry(&sc->ad_stats);
416 disk_destroy(sc->ad_dev_t);
417#ifdef FREEBSD_4
418 if (--disks_registered == 0)
419 cdevsw_remove(&aac_disk_cdevsw);
420#endif
421
422 return(0);
423}
149
150 sc->ad_flags |= AAC_DISK_OPEN;
151 return (0);
152}
153
154/*
155 * Handle last close of the disk device.
156 */
157static int
158aac_disk_close(dev_t dev, int flags, int fmt, d_thread_t *td)
159{
160 struct aac_disk *sc;
161
162 debug_called(4);
163
164 sc = (struct aac_disk *)dev->si_drv1;
165
166 if (sc == NULL)
167 return (ENXIO);
168
169 sc->ad_flags &= ~AAC_DISK_OPEN;
170 return (0);
171}
172
173/*
174 * Handle an I/O request.
175 */
176static void
177aac_disk_strategy(struct bio *bp)
178{
179 struct aac_disk *sc;
180
181 debug_called(4);
182
183 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
184
185 /* bogus disk? */
186 if (sc == NULL) {
187 bp->bio_flags |= BIO_ERROR;
188 bp->bio_error = EINVAL;
189 biodone(bp);
190 return;
191 }
192
193 /* do-nothing operation? */
194 if (bp->bio_bcount == 0) {
195 bp->bio_resid = bp->bio_bcount;
196 biodone(bp);
197 return;
198 }
199
200 /* perform accounting */
201 devstat_start_transaction(&sc->ad_stats);
202
203 /* pass the bio to the controller - it can work out who we are */
204 aac_submit_bio(bp);
205 return;
206}
207
208/*
209 * Map the S/G elements for doing a dump.
210 */
211static void
212aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
213{
214 struct aac_fib *fib;
215 struct aac_blockwrite *bw;
216 struct aac_sg_table *sg;
217 int i;
218
219 fib = (struct aac_fib *)arg;
220 bw = (struct aac_blockwrite *)&fib->data[0];
221 sg = &bw->SgMap;
222
223 if (sg != NULL) {
224 sg->SgCount = nsegs;
225 for (i = 0; i < nsegs; i++) {
226 sg->SgEntry[i].SgAddress = segs[i].ds_addr;
227 sg->SgEntry[i].SgByteCount = segs[i].ds_len;
228 }
229 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
230 }
231}
232
233/*
234 * Dump memory out to an array
235 *
236 * Send out one command at a time with up to AAC_MAXIO of data.
237 */
238static int
239aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length)
240{
241 struct aac_disk *ad;
242 struct aac_softc *sc;
243 struct aac_fib *fib;
244 struct aac_blockwrite *bw;
245 size_t len;
246 int size;
247 static bus_dmamap_t dump_datamap;
248 static int first = 0;
249
250 ad = dev->si_drv1;
251
252 if (ad == NULL)
253 return (EINVAL);
254
255 sc= ad->ad_controller;
256
257 if (!first) {
258 first = 1;
259 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
260 printf("bus_dmamap_create failed\n");
261 return (ENOMEM);
262 }
263 }
264
265 aac_alloc_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
266 bw = (struct aac_blockwrite *)&fib->data[0];
267
268 while (length > 0) {
269 len = (length > AAC_MAXIO) ? AAC_MAXIO : length;
270 bw->Command = VM_CtBlockWrite;
271 bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
272 bw->BlockNumber = offset / AAC_BLOCK_SIZE;
273 bw->ByteCount = len;
274 bw->Stable = CUNSTABLE;
275 bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
276 len, aac_dump_map_sg, fib, 0);
277 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
278 BUS_DMASYNC_PREWRITE);
279
280 /* fib->Header.Size is set in aac_dump_map_sg */
281 size = fib->Header.Size + sizeof(struct aac_blockwrite);
282
283 if (aac_sync_fib(sc, ContainerCommand, 0, fib, size)) {
284 printf("Error dumping block 0x%x\n", physical);
285 return (EIO);
286 }
287 length -= len;
288 offset += len;
289 }
290
291 return (0);
292}
293
294/*
295 * Handle completion of an I/O request.
296 */
297void
298aac_biodone(struct bio *bp)
299{
300 struct aac_disk *sc;
301
302 debug_called(4);
303
304 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
305
306 devstat_end_transaction_bio(&sc->ad_stats, bp);
307 if (bp->bio_flags & BIO_ERROR) {
308#if __FreeBSD_version > 500039
309 disk_err(bp, "hard error", -1, 1);
310#elif __FreeBSD_version > 500005
311 int blkno;
312 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
313 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
314#else
315 int blkno;
316 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
317 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
318#endif
319 }
320 biodone(bp);
321}
322
323/*
324 * Stub only.
325 */
326static int
327aac_disk_probe(device_t dev)
328{
329
330 debug_called(2);
331
332 return (0);
333}
334
335/*
336 * Attach a unit to the controller.
337 */
338static int
339aac_disk_attach(device_t dev)
340{
341 struct aac_disk *sc;
342
343 debug_called(1);
344
345 sc = (struct aac_disk *)device_get_softc(dev);
346
347 /* initialise our softc */
348 sc->ad_controller =
349 (struct aac_softc *)device_get_softc(device_get_parent(dev));
350 sc->ad_container = device_get_ivars(dev);
351 sc->ad_dev = dev;
352
353 /*
354 * require that extended translation be enabled - other drivers read the
355 * disk!
356 */
357 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
358 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
359 sc->ad_heads = 255;
360 sc->ad_sectors = 63;
361 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
362 sc->ad_heads = 128;
363 sc->ad_sectors = 32;
364 } else {
365 sc->ad_heads = 64;
366 sc->ad_sectors = 32;
367 }
368 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
369
370 device_printf(dev, "%uMB (%u sectors)\n",
371 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
372 sc->ad_size);
373
374 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
375 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
376 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
377 DEVSTAT_PRIORITY_ARRAY);
378
379 /* attach a generic disk device to ourselves */
380 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
381 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
382 sc->ad_dev_t->si_drv1 = sc;
383#ifdef FREEBSD_4
384 disks_registered++;
385#endif
386
387 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
388 sc->unit = device_get_unit(dev);
389
390 return (0);
391}
392
393/*
394 * Disconnect ourselves from the system.
395 */
396static int
397aac_disk_detach(device_t dev)
398{
399 struct aac_disk *sc;
400
401 debug_called(2);
402
403 sc = (struct aac_disk *)device_get_softc(dev);
404
405 if (sc->ad_flags & AAC_DISK_OPEN)
406 return(EBUSY);
407
408 devstat_remove_entry(&sc->ad_stats);
409 disk_destroy(sc->ad_dev_t);
410#ifdef FREEBSD_4
411 if (--disks_registered == 0)
412 cdevsw_remove(&aac_disk_cdevsw);
413#endif
414
415 return(0);
416}