aac_disk.c revision 65793
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: head/sys/dev/aac/aac_disk.c 65793 2000-09-13 03:20:35Z msmith $ 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 <machine/clock.h> 42#include <sys/rman.h> 43 44#include <dev/aac/aacreg.h> 45#include <dev/aac/aacvar.h> 46 47/* 48 * Interface to parent. 49 */ 50static int aac_disk_probe(device_t dev); 51static int aac_disk_attach(device_t dev); 52static int aac_disk_detach(device_t dev); 53 54/* 55 * Interface to the device switch. 56 */ 57static d_open_t aac_disk_open; 58static d_close_t aac_disk_close; 59static d_strategy_t aac_disk_strategy; 60 61#define AAC_DISK_CDEV_MAJOR 151 62 63static 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 80devclass_t aac_disk_devclass; 81static struct cdevsw aac_disk_disk_cdevsw; 82#ifdef FREEBSD_4 83static int disks_registered = 0; 84#endif 85 86static 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 93static driver_t aac_disk_driver = { 94 "aacd", 95 aac_disk_methods, 96 sizeof(struct aac_disk) 97}; 98 99DRIVER_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 */ 107static int 108aac_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 */ 140static int 141aac_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 */ 157static void 158aac_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 */ 190void 191aac_complete_bio(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 biodone(bp); 199} 200 201/******************************************************************************** 202 * Stub only. 203 */ 204static int 205aac_disk_probe(device_t dev) 206{ 207 208 debug_called(4); 209 210 return (0); 211} 212 213/******************************************************************************** 214 * Attach a unit to the controller. 215 */ 216static int 217aac_disk_attach(device_t dev) 218{ 219 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 220 int sgspace; 221 int maxsg; 222 223 debug_called(4); 224 225 /* initialise our softc */ 226 sc->ad_controller = (struct aac_softc *)device_get_softc(device_get_parent(dev)); 227 sc->ad_container = device_get_ivars(dev); 228 sc->ad_dev = dev; 229 230 /* require that extended translation be enabled XXX document! */ 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 >= (2 * 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), AAC_BLOCK_SIZE, 248 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, &aac_disk_cdevsw, &aac_disk_disk_cdevsw); 254 sc->ad_dev_t->si_drv1 = sc; 255#ifdef FREEBSD_4 256 disks_registered++; 257#endif 258 259 /* 260 * We can calculate the maximum number of s/g entries based on the size of the 261 * FIB and the command structures packed within it. 262 */ 263 sgspace = (sizeof(struct aac_fib) - sizeof(struct aac_fib_header) - 264 imax(sizeof(struct aac_blockwrite), sizeof(struct aac_blockread))); 265 maxsg = (sgspace - sizeof(struct aac_sg_table)) / sizeof(struct aac_sg_entry); 266 267 /* set the maximum I/O size to the theoretical worst maximum allowed by the S/G list size */ 268 sc->ad_dev_t->si_iosize_max = (maxsg - 1) * PAGE_SIZE; 269 270 return (0); 271} 272 273/******************************************************************************** 274 * Disconnect ourselves from the system. 275 */ 276static int 277aac_disk_detach(device_t dev) 278{ 279 struct aac_disk *sc = (struct aac_disk *)device_get_softc(dev); 280 281 debug_called(4); 282 283 if (sc->ad_flags & AAC_DISK_OPEN) 284 return(EBUSY); 285 286 devstat_remove_entry(&sc->ad_stats); 287#ifdef FREEBSD_4 288 if (--disks_registered == 0) 289 cdevsw_remove(&aac_disk_disk_cdevsw); 290#else 291 disk_destroy(sc->ad_dev_t); 292#endif 293 294 return(0); 295} 296 297