1 /*- 2 * Copyright (c) 2006 IronPort Systems 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: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $ 27 */ 28 29 #include "opt_mfi.h" 30 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/module.h> 35 #include <sys/malloc.h> 36 #include <sys/uio.h> 37 38 #include <sys/buf2.h> 39 #include <sys/bus.h> 40 #include <sys/conf.h> 41 #include <sys/disk.h> 42 43 #include <vm/vm.h> 44 #include <vm/pmap.h> 45 46 #include <machine/md_var.h> 47 #include <sys/rman.h> 48 49 #include <dev/raid/mfi/mfireg.h> 50 #include <dev/raid/mfi/mfi_ioctl.h> 51 #include <dev/raid/mfi/mfivar.h> 52 53 static int mfi_disk_probe(device_t dev); 54 static int mfi_disk_attach(device_t dev); 55 static int mfi_disk_detach(device_t dev); 56 57 static d_open_t mfi_disk_open; 58 static d_close_t mfi_disk_close; 59 static d_strategy_t mfi_disk_strategy; 60 static d_dump_t mfi_disk_dump; 61 62 static struct dev_ops mfi_disk_ops = { 63 { "mfid", 0, D_DISK }, 64 .d_open = mfi_disk_open, 65 .d_close = mfi_disk_close, 66 .d_strategy = mfi_disk_strategy, 67 .d_dump = mfi_disk_dump, 68 }; 69 70 static devclass_t mfi_disk_devclass; 71 72 static device_method_t mfi_disk_methods[] = { 73 DEVMETHOD(device_probe, mfi_disk_probe), 74 DEVMETHOD(device_attach, mfi_disk_attach), 75 DEVMETHOD(device_detach, mfi_disk_detach), 76 { 0, 0 } 77 }; 78 79 static driver_t mfi_disk_driver = { 80 "mfid", 81 mfi_disk_methods, 82 sizeof(struct mfi_disk) 83 }; 84 85 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0); 86 87 static int 88 mfi_disk_probe(device_t dev) 89 { 90 91 return (0); 92 } 93 94 static int 95 mfi_disk_attach(device_t dev) 96 { 97 struct mfi_disk *sc; 98 struct mfi_ld_info *ld_info; 99 struct disk_info info; 100 uint64_t sectors; 101 uint32_t secsize; 102 char *state; 103 104 sc = device_get_softc(dev); 105 ld_info = device_get_ivars(dev); 106 107 sc->ld_dev = dev; 108 sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 109 sc->ld_unit = device_get_unit(dev); 110 sc->ld_info = ld_info; 111 sc->ld_controller = device_get_softc(device_get_parent(dev)); 112 sc->ld_flags = 0; 113 114 sectors = ld_info->size; 115 secsize = MFI_SECTOR_LEN; 116 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 117 TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 118 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 119 120 switch (ld_info->ld_config.params.state) { 121 case MFI_LD_STATE_OFFLINE: 122 state = "offline"; 123 break; 124 case MFI_LD_STATE_PARTIALLY_DEGRADED: 125 state = "partially degraded"; 126 break; 127 case MFI_LD_STATE_DEGRADED: 128 state = "degraded"; 129 break; 130 case MFI_LD_STATE_OPTIMAL: 131 state = "optimal"; 132 break; 133 default: 134 state = "unknown"; 135 break; 136 } 137 device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n", 138 sectors / (1024 * 1024 / secsize), sectors, 139 ld_info->ld_config.properties.name, 140 state); 141 142 devstat_add_entry(&sc->ld_devstat, "mfid", device_get_unit(dev), 143 MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS, 144 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 145 DEVSTAT_PRIORITY_ARRAY); 146 147 sc->ld_disk.d_cdev = disk_create(sc->ld_unit, &sc->ld_disk, 148 &mfi_disk_ops); 149 sc->ld_disk.d_cdev->si_drv1 = sc; 150 sc->ld_disk.d_cdev->si_iosize_max = 151 min(sc->ld_controller->mfi_max_io * secsize, 152 (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE); 153 154 bzero(&info, sizeof(info)); 155 info.d_media_blksize = secsize; /* mandatory */ 156 info.d_media_blocks = sectors; 157 158 if (info.d_media_blocks >= (1 * 1024 * 1024)) { 159 info.d_nheads = 255; 160 info.d_secpertrack = 63; 161 } else { 162 info.d_nheads = 64; 163 info.d_secpertrack = 32; 164 } 165 166 disk_setdiskinfo(&sc->ld_disk, &info); 167 168 return (0); 169 } 170 171 static int 172 mfi_disk_detach(device_t dev) 173 { 174 struct mfi_disk *sc; 175 176 sc = device_get_softc(dev); 177 178 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 179 if (((sc->ld_flags & MFI_DISK_FLAGS_OPEN)) && 180 (sc->ld_controller->mfi_keep_deleted_volumes || 181 sc->ld_controller->mfi_detaching)) { 182 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 183 return (EBUSY); 184 } 185 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 186 187 disk_destroy(&sc->ld_disk); 188 devstat_remove_entry(&sc->ld_devstat); 189 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 190 TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 191 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 192 kfree(sc->ld_info, M_MFIBUF); 193 return (0); 194 } 195 196 static int 197 mfi_disk_open(struct dev_open_args *ap) 198 { 199 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 200 int error; 201 202 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 203 if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED) 204 error = ENXIO; 205 else { 206 sc->ld_flags |= MFI_DISK_FLAGS_OPEN; 207 error = 0; 208 } 209 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 210 211 return (error); 212 } 213 214 static int 215 mfi_disk_close(struct dev_close_args *ap) 216 { 217 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 218 219 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 220 sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN; 221 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 222 223 return (0); 224 } 225 226 int 227 mfi_disk_disable(struct mfi_disk *sc) 228 { 229 230 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 231 if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) { 232 if (sc->ld_controller->mfi_delete_busy_volumes) 233 return (0); 234 device_printf(sc->ld_dev, "Unable to delete busy device\n"); 235 return (EBUSY); 236 } 237 sc->ld_flags |= MFI_DISK_FLAGS_DISABLED; 238 return (0); 239 } 240 241 void 242 mfi_disk_enable(struct mfi_disk *sc) 243 { 244 245 KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0); 246 sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED; 247 } 248 249 static int 250 mfi_disk_strategy(struct dev_strategy_args *ap) 251 { 252 struct bio *bio = ap->a_bio; 253 struct buf *bp = bio->bio_buf; 254 struct mfi_disk *sc = ap->a_head.a_dev->si_drv1; 255 struct mfi_softc *controller; 256 257 if (sc == NULL) { 258 bp->b_error = EINVAL; 259 bp->b_flags |= B_ERROR; 260 bp->b_resid = bp->b_bcount; 261 biodone(bio); 262 return (0); 263 } 264 265 /* 266 * XXX swildner 267 * 268 * If it's a null transfer, do nothing. FreeBSD's original driver 269 * doesn't have this, but that caused hard error messages (even 270 * though everything else continued to work fine). Interestingly, 271 * only when HAMMER was used. 272 * 273 * Several others of our RAID drivers have this check, such as 274 * aac(4) and ida(4), so we insert it here, too. 275 * 276 * The cause of null transfers is yet unknown. 277 */ 278 if (bp->b_bcount == 0) { 279 bp->b_resid = bp->b_bcount; 280 biodone(bio); 281 return (0); 282 } 283 284 controller = sc->ld_controller; 285 bio->bio_driver_info = sc; 286 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 287 mfi_enqueue_bio(controller, bio); 288 devstat_start_transaction(&sc->ld_devstat); 289 mfi_startio(controller); 290 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 291 return (0); 292 } 293 294 void 295 mfi_disk_complete(struct bio *bio) 296 { 297 struct mfi_disk *sc = bio->bio_driver_info; 298 struct buf *bp = bio->bio_buf; 299 300 devstat_end_transaction_buf(&sc->ld_devstat, bp); 301 if (bp->b_flags & B_ERROR) { 302 if (bp->b_error == 0) 303 bp->b_error = EIO; 304 diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1); 305 kprintf("\n"); 306 } else { 307 bp->b_resid = 0; 308 } 309 biodone(bio); 310 } 311 312 static int 313 mfi_disk_dump(struct dev_dump_args *ap) 314 { 315 cdev_t dev = ap->a_head.a_dev; 316 off_t offset = ap->a_offset; 317 void *virt = ap->a_virtual; 318 size_t len = ap->a_length; 319 struct mfi_disk *sc; 320 struct mfi_softc *parent_sc; 321 int error; 322 323 sc = dev->si_drv1; 324 parent_sc = sc->ld_controller; 325 326 if (len > 0) { 327 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 328 MFI_SECTOR_LEN, virt, len)) != 0) 329 return (error); 330 } else { 331 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 332 } 333 334 return (0); 335 } 336