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$ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 36 #include <dev/aac/aac_compat.h> 37 #include <sys/bus.h> 38 #include <sys/conf.h> 39 #include <sys/devicestat.h> 40 #include <sys/disk.h> 41 42 #include <machine/bus.h> 43 #include <sys/rman.h> 44 45 #include <dev/aac/aacreg.h> 46 #include <dev/aac/aac_ioctl.h> 47 #include <dev/aac/aacvar.h> 48 49 /* 50 * Interface to parent. 51 */ 52 static int aac_disk_probe(device_t dev); 53 static int aac_disk_attach(device_t dev); 54 static int aac_disk_detach(device_t dev); 55 56 /* 57 * Interface to the device switch. 58 */ 59 static d_open_t aac_disk_open; 60 static d_close_t aac_disk_close; 61 static d_strategy_t aac_disk_strategy; 62 63 #define AAC_DISK_CDEV_MAJOR 151 64 65 static struct cdevsw aac_disk_cdevsw = { 66 /* open */ aac_disk_open, 67 /* close */ aac_disk_close, 68 /* read */ physread, 69 /* write */ physwrite, 70 /* ioctl */ noioctl, 71 /* poll */ nopoll, 72 /* mmap */ nommap, 73 /* strategy */ aac_disk_strategy, 74 /* name */ "aacd", 75 /* maj */ AAC_DISK_CDEV_MAJOR, 76 /* dump */ nodump, 77 /* psize */ nopsize, 78 /* flags */ D_DISK, 79 }; 80 81 devclass_t aac_disk_devclass; 82 static struct cdevsw aac_disk_disk_cdevsw; 83 #ifdef FREEBSD_4 84 static int disks_registered = 0; 85 #endif 86 87 static device_method_t aac_disk_methods[] = { 88 DEVMETHOD(device_probe, aac_disk_probe), 89 DEVMETHOD(device_attach, aac_disk_attach), 90 DEVMETHOD(device_detach, aac_disk_detach), 91 { 0, 0 } 92 }; 93 94 static driver_t aac_disk_driver = { 95 "aacd", 96 aac_disk_methods, 97 sizeof(struct aac_disk) 98 }; 99 100 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 101 102 /****************************************************************************** 103 * Handle open from generic layer. 104 * 105 * This is called by the diskslice code on first open in order to get the 106 * basic device geometry paramters. 107 */ 108 static int 109 aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p) 110 { 111 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; 112 struct disklabel *label; 113 114 debug_called(4); 115 116 if (sc == NULL) 117 return (ENXIO); 118 119 /* check that the controller is up and running */ 120 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) 121 return(ENXIO); 122 123 /* build synthetic label */ 124 label = &sc->ad_disk.d_label; 125 bzero(label, sizeof(*label)); 126 label->d_type = DTYPE_ESDI; 127 label->d_secsize = AAC_BLOCK_SIZE; 128 label->d_nsectors = sc->ad_sectors; 129 label->d_ntracks = sc->ad_heads; 130 label->d_ncylinders = sc->ad_cylinders; 131 label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 132 label->d_secperunit = sc->ad_size; 133 134 sc->ad_flags |= AAC_DISK_OPEN; 135 return (0); 136 } 137 138 /****************************************************************************** 139 * Handle last close of the disk device. 140 */ 141 static int 142 aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p) 143 { 144 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; 145 146 debug_called(4); 147 148 if (sc == NULL) 149 return (ENXIO); 150 151 sc->ad_flags &= ~AAC_DISK_OPEN; 152 return (0); 153 } 154 155 /****************************************************************************** 156 * Handle an I/O request. 157 */ 158 static void 159 aac_disk_strategy(struct bio *bp) 160 { 161 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; 162 163 debug_called(4); 164 165 /* bogus disk? */ 166 if (sc == NULL) { 167 bp->bio_flags |= BIO_ERROR; 168 bp->bio_error = EINVAL; 169 biodone(bp); 170 return; 171 } 172 173 /* perform accounting */ 174 devstat_start_transaction(&sc->ad_stats); 175 176 /* pass the bio to the controller - it can work out who we are */ 177 aac_submit_bio(bp); 178 return; 179 } 180 181 /****************************************************************************** 182 * Handle completion of an I/O request. 183 */ 184 void 185 aac_biodone(struct bio *bp) 186 { 187 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; 188 189 debug_called(4); 190 191 devstat_end_transaction_bio(&sc->ad_stats, bp); 192 if (bp->bio_flags & BIO_ERROR) 193 diskerr(bp, (char *)bp->bio_driver1, 0, &sc->ad_label); 194 biodone(bp); 195 } 196 197 /****************************************************************************** 198 * Stub only. 199 */ 200 static int 201 aac_disk_probe(device_t dev) 202 { 203 204 debug_called(4); 205 206 return (0); 207 } 208 209 /****************************************************************************** 210 * Attach a unit to the controller. 211 */ 212 static int 213 aac_disk_attach(device_t dev) 214 { 215 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 216 int sgspace; 217 int maxsg; 218 219 debug_called(4); 220 221 /* initialise our softc */ 222 sc->ad_controller = 223 (struct aac_softc *)device_get_softc(device_get_parent(dev)); 224 sc->ad_container = device_get_ivars(dev); 225 sc->ad_dev = dev; 226 227 /* 228 * require that extended translation be enabled - other drivers read the 229 * disk! 230 */ 231 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 232 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 233 sc->ad_heads = 255; 234 sc->ad_sectors = 63; 235 } else if (sc->ad_size >= (1 * 1024 * 1024)) { /* 1GB */ 236 sc->ad_heads = 128; 237 sc->ad_sectors = 32; 238 } else { 239 sc->ad_heads = 64; 240 sc->ad_sectors = 32; 241 } 242 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 243 244 device_printf(dev, "%uMB (%u sectors)\n", 245 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size); 246 247 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), 248 AAC_BLOCK_SIZE, DEVSTAT_NO_ORDERED_TAGS, 249 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 250 DEVSTAT_PRIORITY_ARRAY); 251 252 /* attach a generic disk device to ourselves */ 253 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, 254 &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 255 sc->ad_dev_t->si_drv1 = sc; 256 #ifdef FREEBSD_4 257 disks_registered++; 258 #endif 259 260 /* 261 * We can calculate the maximum number of s/g entries based on the size of 262 * the FIB and the command structures packed within it. 263 */ 264 sgspace = (sizeof(struct aac_fib) - sizeof(struct aac_fib_header) - 265 imax(sizeof(struct aac_blockwrite), 266 sizeof(struct aac_blockread))); 267 maxsg = (sgspace - sizeof(struct aac_sg_table)) / 268 sizeof(struct aac_sg_entry); 269 270 /* 271 * set the maximum I/O size to the theoretical worst maximum allowed by the 272 * S/G list size 273 */ 274 sc->ad_dev_t->si_iosize_max = (maxsg - 1) * PAGE_SIZE; 275 276 return (0); 277 } 278 279 /****************************************************************************** 280 * Disconnect ourselves from the system. 281 */ 282 static int 283 aac_disk_detach(device_t dev) 284 { 285 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 286 287 debug_called(4); 288 289 if (sc->ad_flags & AAC_DISK_OPEN) 290 return(EBUSY); 291 292 devstat_remove_entry(&sc->ad_stats); 293 #ifdef FREEBSD_4 294 if (--disks_registered == 0) 295 cdevsw_remove(&aac_disk_disk_cdevsw); 296 #else 297 disk_destroy(sc->ad_dev_t); 298 #endif 299 300 return(0); 301 } 302 303