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: src/sys/dev/aac/aac_disk.c,v 1.3.2.8 2003/01/11 18:39:39 scottl Exp $ 30 * $DragonFly: src/sys/dev/raid/aac/aac_disk.c,v 1.4 2003/07/22 17:03:27 dillon Exp $ 31 */ 32 33 #include "opt_aac.h" 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/sysctl.h> 39 40 #include <dev/aac/aac_compat.h> 41 #include <sys/bus.h> 42 #include <sys/conf.h> 43 #include <sys/devicestat.h> 44 #include <sys/disk.h> 45 46 #include <vm/vm.h> 47 #include <vm/pmap.h> 48 49 #include <machine/md_var.h> 50 #include <machine/bus.h> 51 #include <sys/rman.h> 52 53 #include <dev/aac/aacreg.h> 54 #include <dev/aac/aac_ioctl.h> 55 #include <dev/aac/aacvar.h> 56 57 /* 58 * Interface to parent. 59 */ 60 static int aac_disk_probe(device_t dev); 61 static int aac_disk_attach(device_t dev); 62 static int aac_disk_detach(device_t dev); 63 64 /* 65 * Interface to the device switch. 66 */ 67 static d_open_t aac_disk_open; 68 static d_close_t aac_disk_close; 69 static d_strategy_t aac_disk_strategy; 70 static d_dump_t aac_disk_dump; 71 72 #define AAC_DISK_CDEV_MAJOR 151 73 74 static struct cdevsw aac_disk_cdevsw = { 75 /* name */ "aacd", 76 /* maj */ AAC_DISK_CDEV_MAJOR, 77 /* flags */ D_DISK, 78 /* port */ NULL, 79 /* autoq */ 0, 80 81 /* open */ aac_disk_open, 82 /* close */ aac_disk_close, 83 /* read */ physread, 84 /* write */ physwrite, 85 /* ioctl */ noioctl, 86 /* poll */ nopoll, 87 /* mmap */ nommap, 88 /* strategy */ aac_disk_strategy, 89 /* dump */ aac_disk_dump, 90 /* psize */ nopsize 91 }; 92 93 devclass_t aac_disk_devclass; 94 95 static device_method_t aac_disk_methods[] = { 96 DEVMETHOD(device_probe, aac_disk_probe), 97 DEVMETHOD(device_attach, aac_disk_attach), 98 DEVMETHOD(device_detach, aac_disk_detach), 99 { 0, 0 } 100 }; 101 102 static driver_t aac_disk_driver = { 103 "aacd", 104 aac_disk_methods, 105 sizeof(struct aac_disk) 106 }; 107 108 #define AAC_MAXIO 65536 109 110 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 111 112 /* sysctl tunables */ 113 static unsigned int aac_iosize_max = AAC_MAXIO; /* due to limits of the card */ 114 TUNABLE_INT("hw.aac.iosize_max", &aac_iosize_max); 115 116 SYSCTL_DECL(_hw_aac); 117 SYSCTL_UINT(_hw_aac, OID_AUTO, iosize_max, CTLFLAG_RD, &aac_iosize_max, 0, 118 "Max I/O size per transfer to an array"); 119 120 /* 121 * Handle open from generic layer. 122 * 123 * This is called by the diskslice code on first open in order to get the 124 * basic device geometry paramters. 125 */ 126 static int 127 aac_disk_open(dev_t dev, int flags, int fmt, d_thread_t *td) 128 { 129 struct aac_disk *sc; 130 struct disklabel *label; 131 132 debug_called(0); 133 134 sc = (struct aac_disk *)dev->si_drv1; 135 136 if (sc == NULL) { 137 printf("aac_disk_open: No Softc\n"); 138 return (ENXIO); 139 } 140 141 /* check that the controller is up and running */ 142 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) { 143 printf("Controller Suspended controller state = 0x%x\n", 144 sc->ad_controller->aac_state); 145 return(ENXIO); 146 } 147 148 /* build synthetic label */ 149 label = &sc->ad_disk.d_label; 150 bzero(label, sizeof(*label)); 151 label->d_type = DTYPE_ESDI; 152 label->d_secsize = AAC_BLOCK_SIZE; 153 label->d_nsectors = sc->ad_sectors; 154 label->d_ntracks = sc->ad_heads; 155 label->d_ncylinders = sc->ad_cylinders; 156 label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 157 label->d_secperunit = sc->ad_size; 158 159 sc->ad_flags |= AAC_DISK_OPEN; 160 return (0); 161 } 162 163 /* 164 * Handle last close of the disk device. 165 */ 166 static int 167 aac_disk_close(dev_t dev, int flags, int fmt, d_thread_t *td) 168 { 169 struct aac_disk *sc; 170 171 debug_called(0); 172 173 sc = (struct aac_disk *)dev->si_drv1; 174 175 if (sc == NULL) 176 return (ENXIO); 177 178 sc->ad_flags &= ~AAC_DISK_OPEN; 179 return (0); 180 } 181 182 /* 183 * Handle an I/O request. 184 */ 185 static void 186 aac_disk_strategy(struct bio *bp) 187 { 188 struct aac_disk *sc; 189 190 debug_called(4); 191 192 sc = (struct aac_disk *)bp->bio_dev->si_drv1; 193 194 /* bogus disk? */ 195 if (sc == NULL) { 196 bp->bio_flags |= BIO_ERROR; 197 bp->bio_error = EINVAL; 198 biodone(bp); 199 return; 200 } 201 202 /* do-nothing operation? */ 203 if (bp->bio_bcount == 0) { 204 bp->bio_resid = bp->bio_bcount; 205 biodone(bp); 206 return; 207 } 208 209 /* perform accounting */ 210 devstat_start_transaction(&sc->ad_stats); 211 212 /* pass the bio to the controller - it can work out who we are */ 213 aac_submit_bio(bp); 214 return; 215 } 216 217 /* 218 * Dump memory out to an array 219 * 220 * This queues blocks of memory of size AAC_MAXIO to the controller and waits 221 * for the controller to complete the requests. 222 */ 223 static int 224 aac_disk_dump(dev_t dev) 225 { 226 struct aac_disk *ad; 227 struct aac_softc *sc; 228 vm_offset_t addr; 229 long blkcnt; 230 unsigned int count, blkno, secsize; 231 int dumppages; 232 int i, error; 233 234 ad = dev->si_drv1; 235 addr = 0; 236 dumppages = AAC_MAXIO / PAGE_SIZE; 237 238 if ((error = disk_dumpcheck(dev, &count, &blkno, &secsize))) 239 return (error); 240 241 if (ad == NULL) 242 return (ENXIO); 243 244 sc= ad->ad_controller; 245 246 blkcnt = howmany(PAGE_SIZE, secsize); 247 248 while (count > 0) { 249 caddr_t va = NULL; 250 251 if ((count / blkcnt) < dumppages) 252 dumppages = count / blkcnt; 253 254 for (i = 0; i < dumppages; ++i) { 255 vm_offset_t a = addr + (i * PAGE_SIZE); 256 if (is_physical_memory(a)) { 257 va = pmap_kenter_temporary(trunc_page(a), i); 258 } else { 259 va = pmap_kenter_temporary(trunc_page(0), i); 260 } 261 } 262 263 retry: 264 /* 265 * Queue the block to the controller. If the queue is full, 266 * EBUSY will be returned. 267 */ 268 error = aac_dump_enqueue(ad, blkno, va, dumppages); 269 if (error && (error != EBUSY)) 270 return (error); 271 272 if (!error) { 273 if (dumpstatus(addr, (off_t)(count * DEV_BSIZE)) < 0) 274 return (EINTR); 275 276 blkno += blkcnt * dumppages; 277 count -= blkcnt * dumppages; 278 addr += PAGE_SIZE * dumppages; 279 if (count > 0) 280 continue; 281 } 282 283 /* 284 * Either the queue was full on the last attemp, or we have no 285 * more data to dump. Let the queue drain out and retry the 286 * block if the queue was full. 287 */ 288 aac_dump_complete(sc); 289 290 if (error == EBUSY) 291 goto retry; 292 } 293 294 return (0); 295 } 296 297 /* 298 * Handle completion of an I/O request. 299 */ 300 void 301 aac_biodone(struct bio *bp) 302 { 303 struct aac_disk *sc; 304 int blkno; 305 306 debug_called(4); 307 308 sc = (struct aac_disk *)bp->bio_dev->si_drv1; 309 310 devstat_end_transaction_bio(&sc->ad_stats, bp); 311 if (bp->bio_flags & BIO_ERROR) { 312 blkno = (sc->ad_label.d_nsectors) ? 0 : -1; 313 #if __FreeBSD_version > 500005 314 diskerr(bp, (char *)bp->bio_driver1, blkno, &sc->ad_label); 315 #else 316 diskerr(bp, (char *)bp->bio_driver1, 0, blkno, &sc->ad_label); 317 #endif 318 } 319 biodone(bp); 320 } 321 322 /* 323 * Stub only. 324 */ 325 static int 326 aac_disk_probe(device_t dev) 327 { 328 329 debug_called(2); 330 331 return (0); 332 } 333 334 /* 335 * Attach a unit to the controller. 336 */ 337 static int 338 aac_disk_attach(device_t dev) 339 { 340 struct aac_disk *sc; 341 342 debug_called(0); 343 344 sc = (struct aac_disk *)device_get_softc(dev); 345 346 /* initialise our softc */ 347 sc->ad_controller = 348 (struct aac_softc *)device_get_softc(device_get_parent(dev)); 349 sc->ad_container = device_get_ivars(dev); 350 sc->ad_dev = dev; 351 352 /* 353 * require that extended translation be enabled - other drivers read the 354 * disk! 355 */ 356 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 357 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 358 sc->ad_heads = 255; 359 sc->ad_sectors = 63; 360 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 361 sc->ad_heads = 128; 362 sc->ad_sectors = 32; 363 } else { 364 sc->ad_heads = 64; 365 sc->ad_sectors = 32; 366 } 367 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 368 369 device_printf(dev, "%uMB (%u sectors)\n", 370 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), 371 sc->ad_size); 372 373 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 374 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 375 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 376 DEVSTAT_PRIORITY_ARRAY); 377 378 /* attach a generic disk device to ourselves */ 379 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 380 &aac_disk_cdevsw); 381 sc->ad_dev_t->si_drv1 = sc; 382 383 sc->ad_dev_t->si_iosize_max = aac_iosize_max; 384 sc->unit = device_get_unit(dev); 385 386 return (0); 387 } 388 389 /* 390 * Disconnect ourselves from the system. 391 */ 392 static int 393 aac_disk_detach(device_t dev) 394 { 395 struct aac_disk *sc; 396 397 debug_called(2); 398 399 sc = (struct aac_disk *)device_get_softc(dev); 400 401 if (sc->ad_flags & AAC_DISK_OPEN) 402 return(EBUSY); 403 404 devstat_remove_entry(&sc->ad_stats); 405 disk_destroy(&sc->ad_disk); 406 return(0); 407 } 408