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