1/*- 2 * Copyright (c) 1999,2000 Jonathan Lemon 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 *
|
26 * $FreeBSD: head/sys/dev/ida/ida_disk.c 59213 2000-04-13 23:42:55Z jlemon $
|
26 * $FreeBSD: head/sys/dev/ida/ida_disk.c 59249 2000-04-15 05:54:02Z phk $ |
27 */ 28 29/* 30 * Disk driver for Compaq SMART RAID adapters. 31 */ 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/malloc.h> 36#include <sys/kernel.h> 37 38#include <sys/buf.h> 39#include <sys/bus.h> 40#include <sys/conf.h> 41#include <sys/devicestat.h> 42#include <sys/disk.h> 43 44#if NPCI > 0 45#include <machine/bus_memio.h> 46#endif 47#include <machine/bus_pio.h> 48#include <machine/bus.h> 49#include <machine/clock.h> 50#include <sys/rman.h> 51 52#include <dev/ida/idareg.h> 53#include <dev/ida/idavar.h> 54 55/* prototypes */ 56static int idprobe(device_t dev); 57static int idattach(device_t dev); 58static int iddetach(device_t dev); 59 60static d_open_t idopen; 61static d_close_t idclose; 62static d_strategy_t idstrategy; 63 64#define ID_BDEV_MAJOR 29 65#define ID_CDEV_MAJOR 109 66 67#define WD_BDEV_MAJOR 0 68#define WD_CDEV_MAJOR 3 69 70static struct cdevsw id_cdevsw = { 71 /* open */ idopen, 72 /* close */ idclose, 73 /* read */ physread, 74 /* write */ physwrite, 75 /* ioctl */ noioctl, 76 /* poll */ nopoll, 77 /* mmap */ nommap, 78 /* strategy */ idstrategy, 79 /* name */ "id", 80 /* maj */ ID_CDEV_MAJOR, 81 /* dump */ nodump, 82 /* psize */ nopsize, 83 /* flags */ D_DISK, 84 /* bmaj */ ID_BDEV_MAJOR 85}; 86 87static devclass_t id_devclass; 88static struct cdevsw iddisk_cdevsw; 89static int disks_registered = 0; 90 91static device_method_t id_methods[] = { 92 DEVMETHOD(device_probe, idprobe), 93 DEVMETHOD(device_attach, idattach), 94 DEVMETHOD(device_detach, iddetach), 95 { 0, 0 } 96}; 97 98static driver_t id_driver = { 99 "idad", 100 id_methods, 101 sizeof(struct id_softc) 102}; 103 104static __inline struct id_softc * 105idgetsoftc(dev_t dev) 106{ 107 108 return ((struct id_softc *)dev->si_drv1); 109} 110 111static int 112idopen(dev_t dev, int flags, int fmt, struct proc *p) 113{ 114 struct id_softc *drv; 115 struct disklabel *label; 116 117 drv = idgetsoftc(dev); 118 if (drv == NULL) 119 return (ENXIO); 120 121 label = &drv->disk.d_label; 122 bzero(label, sizeof(*label)); 123 label->d_type = DTYPE_SCSI; 124 label->d_secsize = drv->secsize; 125 label->d_nsectors = drv->sectors; 126 label->d_ntracks = drv->heads; 127 label->d_ncylinders = drv->cylinders; 128 label->d_secpercyl = drv->sectors * drv->heads; 129 label->d_secperunit = drv->secperunit; 130 131 return (0); 132} 133 134static int 135idclose(dev_t dev, int flags, int fmt, struct proc *p) 136{ 137 struct id_softc *drv; 138 139 drv = idgetsoftc(dev); 140 if (drv == NULL) 141 return (ENXIO); 142 return (0); 143} 144 145/* 146 * Read/write routine for a buffer. Finds the proper unit, range checks 147 * arguments, and schedules the transfer. Does not wait for the transfer 148 * to complete. Multi-page transfers are supported. All I/O requests must 149 * be a multiple of a sector in length. 150 */ 151static void
|
152idstrategy(struct buf *bp)
|
152idstrategy(struct bio *bp) |
153{ 154 struct id_softc *drv; 155 int s; 156
|
157 drv = idgetsoftc(bp->b_dev);
|
157 drv = idgetsoftc(bp->bio_dev); |
158 if (drv == NULL) {
|
159 bp->b_error = EINVAL;
|
159 bp->bio_error = EINVAL; |
160 goto bad; 161 } 162 163 /* 164 * software write protect check 165 */
|
166 if (drv->flags & DRV_WRITEPROT && (bp->b_iocmd == BIO_WRITE)) {
167 bp->b_error = EROFS;
|
166 if (drv->flags & DRV_WRITEPROT && (bp->bio_cmd == BIO_WRITE)) { 167 bp->bio_error = EROFS; |
168 goto bad; 169 } 170 171 /* 172 * If it's a null transfer, return immediately 173 */
|
174 if (bp->b_bcount == 0)
|
174 if (bp->bio_bcount == 0) |
175 goto done; 176
|
177 bp->b_driver1 = drv;
|
177 bp->bio_driver1 = drv; |
178 s = splbio(); 179 devstat_start_transaction(&drv->stats); 180 ida_submit_buf(drv->controller, bp); 181 splx(s); 182 return; 183 184bad:
|
185 bp->b_ioflags |= BIO_ERROR;
|
185 bp->bio_flags |= BIO_ERROR; |
186 187done: 188 /* 189 * Correctly set the buf to indicate a completed transfer 190 */
|
191 bp->b_resid = bp->b_bcount;
|
191 bp->bio_resid = bp->bio_bcount; |
192 biodone(bp); 193 return; 194} 195 196void
|
197id_intr(struct buf *bp)
|
197id_intr(struct bio *bp) |
198{
|
199 struct id_softc *drv = (struct id_softc *)bp->b_driver1;
|
199 struct id_softc *drv = (struct id_softc *)bp->bio_driver1; |
200
|
201 if (bp->b_ioflags & BIO_ERROR)
202 bp->b_error = EIO;
|
201 if (bp->bio_flags & BIO_ERROR) 202 bp->bio_error = EIO; |
203 else
|
204 bp->b_resid = 0;
|
204 bp->bio_resid = 0; |
205
|
206 devstat_end_transaction_buf(&drv->stats, bp);
|
206 devstat_end_transaction_bio(&drv->stats, bp); |
207 biodone(bp); 208} 209 210static int 211idprobe(device_t dev) 212{ 213 214 device_set_desc(dev, "Compaq Logical Drive"); 215 return (0); 216} 217 218static int 219idattach(device_t dev) 220{ 221 struct ida_drive_info dinfo; 222 struct id_softc *drv; 223 device_t parent; 224 dev_t dsk; 225 int error; 226 227 drv = (struct id_softc *)device_get_softc(dev); 228 parent = device_get_parent(dev); 229 drv->controller = (struct ida_softc *)device_get_softc(parent); 230 drv->unit = device_get_unit(dev); 231 232 error = ida_command(drv->controller, CMD_GET_LOG_DRV_INFO, 233 &dinfo, sizeof(dinfo), drv->unit, DMA_DATA_IN); 234 if (error) { 235 device_printf(dev, "CMD_GET_LOG_DRV_INFO failed\n"); 236 return (ENXIO); 237 } 238 239 drv->cylinders = dinfo.ncylinders; 240 drv->heads = dinfo.nheads; 241 drv->sectors = dinfo.nsectors; 242 drv->secsize = dinfo.secsize; 243 drv->secperunit = dinfo.secperunit; 244 245 /* XXX 246 * other initialization 247 */ 248 device_printf(dev, "%uMB (%u sectors), blocksize=%d\n", 249 drv->secperunit / ((1024 * 1024) / drv->secsize), 250 drv->secperunit, drv->secsize); 251 252 devstat_add_entry(&drv->stats, "idad", drv->unit, drv->secsize, 253 DEVSTAT_NO_ORDERED_TAGS, 254 DEVSTAT_TYPE_STORARRAY| DEVSTAT_TYPE_IF_OTHER, 255 DEVSTAT_PRIORITY_ARRAY); 256 257 dsk = disk_create(drv->unit, &drv->disk, 0, 258 &id_cdevsw, &iddisk_cdevsw); 259 260 dsk->si_drv1 = drv; 261 dsk->si_iosize_max = DFLTPHYS; /* XXX guess? */ 262 disks_registered++; 263 264 return (0); 265} 266 267static int 268iddetach(device_t dev) 269{ 270 struct id_softc *drv; 271 272 drv = (struct id_softc *)device_get_softc(dev); 273 devstat_remove_entry(&drv->stats); 274 275 if (--disks_registered == 0) 276 cdevsw_remove(&iddisk_cdevsw); 277 return (0); 278} 279 280DRIVER_MODULE(idad, ida, id_driver, id_devclass, 0, 0);
|