Deleted Added
full compact
aac_disk.c (93495) aac_disk.c (95350)
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 93495 2002-03-31 22:29:52Z phk $
29 * $FreeBSD: head/sys/dev/aac/aac_disk.c 95350 2002-04-24 05:12:50Z 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
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
111DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
112
113/* sysctl tunables */
113DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0);
114
115/* sysctl tunables */
114static unsigned int aac_iosize_max = 65536; /* due to limits of the card */
116static unsigned int aac_iosize_max = AAC_MAXIO; /* 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
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
121#define AAC_MAXIO 65536
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
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;
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/*
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
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;
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/*
216 * Dump memory out to an array
217 *
241 * Dump memory out to an array
242 *
218 * This queues blocks of memory of size AAC_MAXIO to the controller and waits
219 * for the controller to complete the requests.
243 * Send out one command at a time with up to AAC_MAXIO of data.
220 */
221static int
222aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length)
223{
244 */
245static int
246aac_disk_dump(dev_t dev, void *virtual, vm_offset_t physical, off_t offset, size_t length)
247{
224
225 /* XXX: This needs modified for the new dump API */
226 return (ENXIO);
227#if 0
228 struct aac_disk *ad;
229 struct aac_softc *sc;
248 struct aac_disk *ad;
249 struct aac_softc *sc;
230 vm_offset_t addr;
231 long blkcnt;
232 unsigned int count, blkno, secsize;
233 int dumppages;
234 int i, error;
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;
235
236 ad = dev->si_drv1;
256
257 ad = dev->si_drv1;
237 addr = 0;
238 dumppages = AAC_MAXIO / PAGE_SIZE;
239
258
240 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize)))
241 return (error);
242
243 if (ad == NULL)
259 if (ad == NULL)
244 return (ENXIO);
260 return (EINVAL);
245
246 sc= ad->ad_controller;
247
261
262 sc= ad->ad_controller;
263
248 blkcnt = howmany(PAGE_SIZE, secsize);
249
250 while (count > 0) {
251 caddr_t va = NULL;
252
253 if ((count / blkcnt) < dumppages)
254 dumppages = count / blkcnt;
255
256 for (i = 0; i < dumppages; ++i) {
257 vm_offset_t a = addr + (i * PAGE_SIZE);
258 if (is_physical_memory(a)) {
259 va = pmap_kenter_temporary(trunc_page(a), i);
260 } else {
261 va = pmap_kenter_temporary(trunc_page(0), i);
262 }
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);
263 }
269 }
270 }
264
271
265retry:
266 /*
267 * Queue the block to the controller. If the queue is full,
268 * EBUSY will be returned.
269 */
270 error = aac_dump_enqueue(ad, blkno, va, dumppages);
271 if (error && (error != EBUSY))
272 return (error);
272 aac_get_sync_fib(sc, &fib, AAC_SYNC_LOCK_FORCE);
273 bw = (struct aac_blockwrite *)&fib->data[0];
273
274
274 if (!error) {
275 if (dumpstatus(addr, (off_t)(count * DEV_BSIZE)) < 0)
276 return (EINTR);
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);
277
286
278 blkno += blkcnt * dumppages;
279 count -= blkcnt * dumppages;
280 addr += PAGE_SIZE * dumppages;
281 if (count > 0)
282 continue;
283 }
287 /* fib->Header.Size is set in aac_dump_map_sg */
288 size = fib->Header.Size + sizeof(struct aac_blockwrite);
284
289
285 /*
286 * Either the queue was full on the last attemp, or we have no
287 * more data to dump. Let the queue drain out and retry the
288 * block if the queue was full.
289 */
290 aac_dump_complete(sc);
291
292 if (error == EBUSY)
293 goto retry;
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;
294 }
295
296 return (0);
296 }
297
298 return (0);
297#endif
298}
299
300/*
301 * Handle completion of an I/O request.
302 */
303void
304aac_biodone(struct bio *bp)
305{
306 struct aac_disk *sc;
307 int blkno;
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 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
316#if __FreeBSD_version > 500005
317 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
318#else
319 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
320#endif
321 }
322 biodone(bp);
323}
324
325/*
326 * Stub only.
327 */
328static int
329aac_disk_probe(device_t dev)
330{
331
332 debug_called(2);
333
334 return (0);
335}
336
337/*
338 * Attach a unit to the controller.
339 */
340static int
341aac_disk_attach(device_t dev)
342{
343 struct aac_disk *sc;
344
345 debug_called(1);
346
347 sc = (struct aac_disk *)device_get_softc(dev);
348
349 /* initialise our softc */
350 sc->ad_controller =
351 (struct aac_softc *)device_get_softc(device_get_parent(dev));
352 sc->ad_container = device_get_ivars(dev);
353 sc->ad_dev = dev;
354
355 /*
356 * require that extended translation be enabled - other drivers read the
357 * disk!
358 */
359 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
360 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
361 sc->ad_heads = 255;
362 sc->ad_sectors = 63;
363 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
364 sc->ad_heads = 128;
365 sc->ad_sectors = 32;
366 } else {
367 sc->ad_heads = 64;
368 sc->ad_sectors = 32;
369 }
370 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
371
372 device_printf(dev, "%uMB (%u sectors)\n",
373 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
374 sc->ad_size);
375
376 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
377 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
378 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
379 DEVSTAT_PRIORITY_ARRAY);
380
381 /* attach a generic disk device to ourselves */
382 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
383 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
384 sc->ad_dev_t->si_drv1 = sc;
385#ifdef FREEBSD_4
386 disks_registered++;
387#endif
388
389 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
390 sc->unit = device_get_unit(dev);
391
392 return (0);
393}
394
395/*
396 * Disconnect ourselves from the system.
397 */
398static int
399aac_disk_detach(device_t dev)
400{
401 struct aac_disk *sc;
402
403 debug_called(2);
404
405 sc = (struct aac_disk *)device_get_softc(dev);
406
407 if (sc->ad_flags & AAC_DISK_OPEN)
408 return(EBUSY);
409
410 devstat_remove_entry(&sc->ad_stats);
411 disk_destroy(sc->ad_dev_t);
412#ifdef FREEBSD_4
413 if (--disks_registered == 0)
414 cdevsw_remove(&aac_disk_cdevsw);
415#endif
416
417 return(0);
418}
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 int blkno;
309
310 debug_called(4);
311
312 sc = (struct aac_disk *)bp->bio_dev->si_drv1;
313
314 devstat_end_transaction_bio(&sc->ad_stats, bp);
315 if (bp->bio_flags & BIO_ERROR) {
316 blkno = (sc->ad_label.d_nsectors) ? 0 : -1;
317#if __FreeBSD_version > 500005
318 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label);
319#else
320 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label);
321#endif
322 }
323 biodone(bp);
324}
325
326/*
327 * Stub only.
328 */
329static int
330aac_disk_probe(device_t dev)
331{
332
333 debug_called(2);
334
335 return (0);
336}
337
338/*
339 * Attach a unit to the controller.
340 */
341static int
342aac_disk_attach(device_t dev)
343{
344 struct aac_disk *sc;
345
346 debug_called(1);
347
348 sc = (struct aac_disk *)device_get_softc(dev);
349
350 /* initialise our softc */
351 sc->ad_controller =
352 (struct aac_softc *)device_get_softc(device_get_parent(dev));
353 sc->ad_container = device_get_ivars(dev);
354 sc->ad_dev = dev;
355
356 /*
357 * require that extended translation be enabled - other drivers read the
358 * disk!
359 */
360 sc->ad_size = sc->ad_container->co_mntobj.Capacity;
361 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */
362 sc->ad_heads = 255;
363 sc->ad_sectors = 63;
364 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */
365 sc->ad_heads = 128;
366 sc->ad_sectors = 32;
367 } else {
368 sc->ad_heads = 64;
369 sc->ad_sectors = 32;
370 }
371 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
372
373 device_printf(dev, "%uMB (%u sectors)\n",
374 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
375 sc->ad_size);
376
377 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev),
378 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS,
379 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
380 DEVSTAT_PRIORITY_ARRAY);
381
382 /* attach a generic disk device to ourselves */
383 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0,
384 &aac_disk_cdevsw, &aac_disk_disk_cdevsw);
385 sc->ad_dev_t->si_drv1 = sc;
386#ifdef FREEBSD_4
387 disks_registered++;
388#endif
389
390 sc->ad_dev_t->si_iosize_max = aac_iosize_max;
391 sc->unit = device_get_unit(dev);
392
393 return (0);
394}
395
396/*
397 * Disconnect ourselves from the system.
398 */
399static int
400aac_disk_detach(device_t dev)
401{
402 struct aac_disk *sc;
403
404 debug_called(2);
405
406 sc = (struct aac_disk *)device_get_softc(dev);
407
408 if (sc->ad_flags & AAC_DISK_OPEN)
409 return(EBUSY);
410
411 devstat_remove_entry(&sc->ad_stats);
412 disk_destroy(sc->ad_dev_t);
413#ifdef FREEBSD_4
414 if (--disks_registered == 0)
415 cdevsw_remove(&aac_disk_cdevsw);
416#endif
417
418 return(0);
419}