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