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