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.11 2006/02/17 19:18:05 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 "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 "aacreg.h" 54 #include "aac_ioctl.h" 55 #include "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 /* clone */ NULL, 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(dev_t dev, struct bio *bio) 187 { 188 struct buf *bp = bio->bio_buf; 189 struct aac_disk *sc; 190 191 debug_called(4); 192 193 sc = (struct aac_disk *)dev->si_drv1; 194 195 /* bogus disk? */ 196 if (sc == NULL) { 197 bp->b_flags |= B_ERROR; 198 bp->b_error = EINVAL; 199 biodone(bio); 200 return; 201 } 202 203 /* do-nothing operation? */ 204 if (bp->b_bcount == 0) { 205 bp->b_resid = bp->b_bcount; 206 biodone(bio); 207 return; 208 } 209 210 /* perform accounting */ 211 devstat_start_transaction(&sc->ad_stats); 212 213 /* pass the bio to the controller - it can work out who we are */ 214 aac_submit_bio(sc, bio); 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, u_int count, u_int blkno, u_int secsize) 225 { 226 struct aac_disk *ad; 227 struct aac_softc *sc; 228 vm_offset_t addr; 229 long blkcnt; 230 int dumppages; 231 int i, error; 232 233 ad = dev->si_drv1; 234 addr = 0; 235 dumppages = AAC_MAXIO / PAGE_SIZE; 236 237 if (ad == NULL) 238 return (ENXIO); 239 240 sc= ad->ad_controller; 241 242 blkcnt = howmany(PAGE_SIZE, secsize); 243 244 while (count > 0) { 245 caddr_t va = NULL; 246 247 if ((count / blkcnt) < dumppages) 248 dumppages = count / blkcnt; 249 250 for (i = 0; i < dumppages; ++i) { 251 vm_offset_t a = addr + (i * PAGE_SIZE); 252 if (is_physical_memory(a)) { 253 va = pmap_kenter_temporary(trunc_page(a), i); 254 } else { 255 va = pmap_kenter_temporary(trunc_page(0), i); 256 } 257 } 258 259 retry: 260 /* 261 * Queue the block to the controller. If the queue is full, 262 * EBUSY will be returned. 263 */ 264 error = aac_dump_enqueue(ad, blkno, va, dumppages); 265 if (error && (error != EBUSY)) 266 return (error); 267 268 if (!error) { 269 if (dumpstatus(addr, (off_t)(count * DEV_BSIZE)) < 0) 270 return (EINTR); 271 272 blkno += blkcnt * dumppages; 273 count -= blkcnt * dumppages; 274 addr += PAGE_SIZE * dumppages; 275 if (count > 0) 276 continue; 277 } 278 279 /* 280 * Either the queue was full on the last attemp, or we have no 281 * more data to dump. Let the queue drain out and retry the 282 * block if the queue was full. 283 */ 284 aac_dump_complete(sc); 285 286 if (error == EBUSY) 287 goto retry; 288 } 289 290 return (0); 291 } 292 293 /* 294 * Handle completion of an I/O request. 295 */ 296 void 297 aac_biodone(struct bio *bio, const char *code) 298 { 299 struct buf *bp = bio->bio_buf; 300 struct aac_disk *sc; 301 int blkno; 302 303 debug_called(4); 304 305 sc = (struct aac_disk *)bio->bio_driver_info; 306 307 devstat_end_transaction_buf(&sc->ad_stats, bp); 308 if (bp->b_flags & B_ERROR) { 309 blkno = (sc->ad_label.d_nsectors) ? 0 : -1; 310 #if defined(__FreeBSD__) && __FreeBSD_version > 500005 311 diskerr(bio, sc->ad_dev_t, 312 code, blkno, &sc->ad_label); 313 #else 314 diskerr(bio, sc->ad_dev_t, 315 code, 0, blkno, &sc->ad_label); 316 #endif 317 } 318 biodone(bio); 319 } 320 321 /* 322 * Stub only. 323 */ 324 static int 325 aac_disk_probe(device_t dev) 326 { 327 328 debug_called(2); 329 330 return (0); 331 } 332 333 /* 334 * Attach a unit to the controller. 335 */ 336 static int 337 aac_disk_attach(device_t dev) 338 { 339 struct aac_disk *sc; 340 341 debug_called(0); 342 343 sc = (struct aac_disk *)device_get_softc(dev); 344 345 /* initialise our softc */ 346 sc->ad_controller = 347 (struct aac_softc *)device_get_softc(device_get_parent(dev)); 348 sc->ad_container = device_get_ivars(dev); 349 sc->ad_dev = dev; 350 351 /* 352 * require that extended translation be enabled - other drivers read the 353 * disk! 354 */ 355 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 356 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 357 sc->ad_heads = 255; 358 sc->ad_sectors = 63; 359 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 360 sc->ad_heads = 128; 361 sc->ad_sectors = 32; 362 } else { 363 sc->ad_heads = 64; 364 sc->ad_sectors = 32; 365 } 366 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 367 368 device_printf(dev, "%uMB (%u sectors)\n", 369 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), 370 sc->ad_size); 371 372 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 373 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 374 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 375 DEVSTAT_PRIORITY_ARRAY); 376 377 /* attach a generic disk device to ourselves */ 378 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 379 &aac_disk_cdevsw); 380 sc->ad_dev_t->si_drv1 = sc; 381 382 sc->ad_dev_t->si_iosize_max = aac_iosize_max; 383 sc->unit = device_get_unit(dev); 384 385 return (0); 386 } 387 388 /* 389 * Disconnect ourselves from the system. 390 */ 391 static int 392 aac_disk_detach(device_t dev) 393 { 394 struct aac_disk *sc; 395 396 debug_called(2); 397 398 sc = (struct aac_disk *)device_get_softc(dev); 399 400 if (sc->ad_flags & AAC_DISK_OPEN) 401 return(EBUSY); 402 403 devstat_remove_entry(&sc->ad_stats); 404 disk_destroy(&sc->ad_disk); 405 return(0); 406 } 407