1 /*- 2 * Copyright (c) 2000 Michael Smith 3 * Copyright (c) 2000 BSDi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 34 #include <dev/aac/aac_compat.h> 35 #include <sys/bus.h> 36 #include <sys/conf.h> 37 #include <sys/devicestat.h> 38 #include <sys/disk.h> 39 40 #include <machine/bus.h> 41 #include <sys/rman.h> 42 43 #include <dev/aac/aacreg.h> 44 #include <dev/aac/aacvar.h> 45 46 /* 47 * Interface to parent. 48 */ 49 static int aac_disk_probe(device_t dev); 50 static int aac_disk_attach(device_t dev); 51 static int aac_disk_detach(device_t dev); 52 53 /* 54 * Interface to the device switch. 55 */ 56 static d_open_t aac_disk_open; 57 static d_close_t aac_disk_close; 58 static d_strategy_t aac_disk_strategy; 59 60 #define AAC_DISK_CDEV_MAJOR 151 61 62 static struct cdevsw aac_disk_cdevsw = { 63 /* open */ aac_disk_open, 64 /* close */ aac_disk_close, 65 /* read */ physread, 66 /* write */ physwrite, 67 /* ioctl */ noioctl, 68 /* poll */ nopoll, 69 /* mmap */ nommap, 70 /* strategy */ aac_disk_strategy, 71 /* name */ "aacd", 72 /* maj */ AAC_DISK_CDEV_MAJOR, 73 /* dump */ nodump, 74 /* psize */ nopsize, 75 /* flags */ D_DISK, 76 /* bmaj */ -1 77 }; 78 79 devclass_t aac_disk_devclass; 80 static struct cdevsw aac_disk_disk_cdevsw; 81 #ifdef FREEBSD_4 82 static int disks_registered = 0; 83 #endif 84 85 static device_method_t aac_disk_methods[] = { 86 DEVMETHOD(device_probe, aac_disk_probe), 87 DEVMETHOD(device_attach, aac_disk_attach), 88 DEVMETHOD(device_detach, aac_disk_detach), 89 { 0, 0 } 90 }; 91 92 static driver_t aac_disk_driver = { 93 "aacd", 94 aac_disk_methods, 95 sizeof(struct aac_disk) 96 }; 97 98 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, 0, 0); 99 100 /******************************************************************************** 101 * Handle open from generic layer. 102 * 103 * This is called by the diskslice code on first open in order to get the 104 * basic device geometry paramters. 105 */ 106 static int 107 aac_disk_open(dev_t dev, int flags, int fmt, struct proc *p) 108 { 109 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; 110 struct disklabel *label; 111 112 debug_called(4); 113 114 if (sc == NULL) 115 return (ENXIO); 116 117 /* check that the controller is up and running */ 118 if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) 119 return(ENXIO); 120 121 /* build synthetic label */ 122 label = &sc->ad_disk.d_label; 123 bzero(label, sizeof(*label)); 124 label->d_type = DTYPE_ESDI; 125 label->d_secsize = AAC_BLOCK_SIZE; 126 label->d_nsectors = sc->ad_sectors; 127 label->d_ntracks = sc->ad_heads; 128 label->d_ncylinders = sc->ad_cylinders; 129 label->d_secpercyl = sc->ad_sectors * sc->ad_heads; 130 label->d_secperunit = sc->ad_size; 131 132 sc->ad_flags |= AAC_DISK_OPEN; 133 return (0); 134 } 135 136 /******************************************************************************** 137 * Handle last close of the disk device. 138 */ 139 static int 140 aac_disk_close(dev_t dev, int flags, int fmt, struct proc *p) 141 { 142 struct aac_disk *sc = (struct aac_disk *)dev->si_drv1; 143 144 debug_called(4); 145 146 if (sc == NULL) 147 return (ENXIO); 148 149 sc->ad_flags &= ~AAC_DISK_OPEN; 150 return (0); 151 } 152 153 /******************************************************************************** 154 * Handle an I/O request. 155 */ 156 static void 157 aac_disk_strategy(struct bio *bp) 158 { 159 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; 160 161 debug_called(4); 162 163 /* bogus disk? */ 164 if (sc == NULL) { 165 bp->bio_flags |= BIO_ERROR; 166 bp->bio_error = EINVAL; 167 biodone(bp); 168 return; 169 } 170 171 /* do-nothing operation? */ 172 if (bp->bio_bcount == 0) { 173 bp->bio_resid = bp->bio_bcount; 174 biodone(bp); 175 return; 176 } 177 178 /* perform accounting */ 179 devstat_start_transaction(&sc->ad_stats); 180 181 /* pass the bio to the controller - it can work out who we are */ 182 aac_submit_bio(bp); 183 return; 184 } 185 186 /******************************************************************************** 187 * Handle completion of an I/O request. 188 */ 189 void 190 aac_complete_bio(struct bio *bp) 191 { 192 struct aac_disk *sc = (struct aac_disk *)bp->bio_dev->si_drv1; 193 194 debug_called(4); 195 196 devstat_end_transaction_bio(&sc->ad_stats, bp); 197 biodone(bp); 198 } 199 200 /******************************************************************************** 201 * Stub only. 202 */ 203 static int 204 aac_disk_probe(device_t dev) 205 { 206 207 debug_called(4); 208 209 return (0); 210 } 211 212 /******************************************************************************** 213 * Attach a unit to the controller. 214 */ 215 static int 216 aac_disk_attach(device_t dev) 217 { 218 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 219 int sgspace; 220 int maxsg; 221 222 debug_called(4); 223 224 /* initialise our softc */ 225 sc->ad_controller = (struct aac_softc *)device_get_softc(device_get_parent(dev)); 226 sc->ad_container = device_get_ivars(dev); 227 sc->ad_dev = dev; 228 229 /* require that extended translation be enabled XXX document! */ 230 sc->ad_size = sc->ad_container->co_mntobj.Capacity; 231 if (sc->ad_size >= (2 * 1024 * 1024)) { /* 2GB */ 232 sc->ad_heads = 255; 233 sc->ad_sectors = 63; 234 } else if (sc->ad_size >= (2 * 1024 * 1024)) { /* 1GB */ 235 sc->ad_heads = 128; 236 sc->ad_sectors = 32; 237 } else { 238 sc->ad_heads = 64; 239 sc->ad_sectors = 32; 240 } 241 sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors)); 242 243 device_printf(dev, "%uMB (%u sectors)\n", 244 sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE), sc->ad_size); 245 246 devstat_add_entry(&sc->ad_stats, "aacd", device_get_unit(dev), AAC_BLOCK_SIZE, 247 DEVSTAT_NO_ORDERED_TAGS, 248 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 249 DEVSTAT_PRIORITY_ARRAY); 250 251 /* attach a generic disk device to ourselves */ 252 sc->ad_dev_t = disk_create(device_get_unit(dev), &sc->ad_disk, 0, &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 253 sc->ad_dev_t->si_drv1 = sc; 254 #ifdef FREEBSD_4 255 disks_registered++; 256 #endif 257 258 /* 259 * We can calculate the maximum number of s/g entries based on the size of the 260 * FIB and the command structures packed within it. 261 */ 262 sgspace = (sizeof(struct aac_fib) - sizeof(struct aac_fib_header) - 263 imax(sizeof(struct aac_blockwrite), sizeof(struct aac_blockread))); 264 maxsg = (sgspace - sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_entry); 265 266 /* set the maximum I/O size to the theoretical worst maximum allowed by the S/G list size */ 267 sc->ad_dev_t->si_iosize_max = (maxsg - 1) * PAGE_SIZE; 268 269 return (0); 270 } 271 272 /******************************************************************************** 273 * Disconnect ourselves from the system. 274 */ 275 static int 276 aac_disk_detach(device_t dev) 277 { 278 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 279 280 debug_called(4); 281 282 if (sc->ad_flags & AAC_DISK_OPEN) 283 return(EBUSY); 284 285 devstat_remove_entry(&sc->ad_stats); 286 #ifdef FREEBSD_4 287 if (--disks_registered == 0) 288 cdevsw_remove(&aac_disk_disk_cdevsw); 289 #else 290 disk_destroy(sc->ad_dev_t); 291 #endif 292 293 return(0); 294 } 295 296