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