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 * FreeBSD projects/head_mfi/ r232888 28 */ 29 30 #include "opt_mfi.h" 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/malloc.h> 37 #include <sys/uio.h> 38 39 #include <sys/buf2.h> 40 #include <sys/bus.h> 41 #include <sys/conf.h> 42 #include <sys/disk.h> 43 44 #include <vm/vm.h> 45 #include <vm/pmap.h> 46 47 #include <machine/md_var.h> 48 #include <sys/rman.h> 49 50 #include <dev/raid/mfi/mfireg.h> 51 #include <dev/raid/mfi/mfi_ioctl.h> 52 #include <dev/raid/mfi/mfivar.h> 53 54 static int mfi_disk_probe(device_t dev); 55 static int mfi_disk_attach(device_t dev); 56 static int mfi_disk_detach(device_t dev); 57 58 static d_open_t mfi_disk_open; 59 static d_close_t mfi_disk_close; 60 static d_strategy_t mfi_disk_strategy; 61 static d_dump_t mfi_disk_dump; 62 63 static struct dev_ops mfi_disk_ops = { 64 { "mfid", 0, D_DISK | D_MPSAFE }, 65 .d_open = mfi_disk_open, 66 .d_close = mfi_disk_close, 67 .d_strategy = mfi_disk_strategy, 68 .d_dump = mfi_disk_dump, 69 }; 70 71 static devclass_t mfi_disk_devclass; 72 73 static device_method_t mfi_disk_methods[] = { 74 DEVMETHOD(device_probe, mfi_disk_probe), 75 DEVMETHOD(device_attach, mfi_disk_attach), 76 DEVMETHOD(device_detach, mfi_disk_detach), 77 DEVMETHOD_END 78 }; 79 80 static driver_t mfi_disk_driver = { 81 "mfid", 82 mfi_disk_methods, 83 sizeof(struct mfi_disk) 84 }; 85 86 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, NULL, NULL); 87 88 static int 89 mfi_disk_probe(device_t dev) 90 { 91 92 return (0); 93 } 94 95 static int 96 mfi_disk_attach(device_t dev) 97 { 98 struct mfi_disk *sc; 99 struct mfi_ld_info *ld_info; 100 struct disk_info info; 101 uint64_t sectors; 102 uint32_t secsize; 103 char *state; 104 105 sc = device_get_softc(dev); 106 ld_info = device_get_ivars(dev); 107 108 sc->ld_dev = dev; 109 sc->ld_id = ld_info->ld_config.properties.ld.v.target_id; 110 sc->ld_unit = device_get_unit(dev); 111 sc->ld_info = ld_info; 112 sc->ld_controller = device_get_softc(device_get_parent(dev)); 113 sc->ld_flags = 0; 114 115 sectors = ld_info->size; 116 secsize = MFI_SECTOR_LEN; 117 lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE); 118 TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link); 119 lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE); 120 121 switch (ld_info->ld_config.params.state) { 122 case MFI_LD_STATE_OFFLINE: 123 state = "offline"; 124 break; 125 case MFI_LD_STATE_PARTIALLY_DEGRADED: 126 state = "partially degraded"; 127 break; 128 case MFI_LD_STATE_DEGRADED: 129 state = "degraded"; 130 break; 131 case MFI_LD_STATE_OPTIMAL: 132 state = "optimal"; 133 break; 134 default: 135 state = "unknown"; 136 break; 137 } 138 device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n", 139 sectors / (1024 * 1024 / secsize), sectors, 140 ld_info->ld_config.properties.name, 141 state); 142 143 devstat_add_entry(&sc->ld_devstat, "mfid", device_get_unit(dev), 144 MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS, 145 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 146 DEVSTAT_PRIORITY_ARRAY); 147 148 sc->ld_dev_t = disk_create(sc->ld_unit, &sc->ld_disk, &mfi_disk_ops); 149 sc->ld_dev_t->si_drv1 = sc; 150 sc->ld_dev_t->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 mfi_lockassert(&sc->ld_controller->mfi_io_lock); 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 ld 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 mfi_lockassert(&sc->ld_controller->mfi_io_lock); 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 controller = sc->ld_controller; 265 266 if (controller->hw_crit_error) { 267 bp->b_error = EBUSY; 268 return (0); 269 } 270 271 if (controller->issuepend_done == 0) { 272 bp->b_error = EBUSY; 273 return (0); 274 } 275 276 /* 277 * XXX swildner 278 * 279 * If it's a null transfer, do nothing. FreeBSD's original driver 280 * doesn't have this, but that caused hard error messages (even 281 * though everything else continued to work fine). Interestingly, 282 * only when HAMMER was used. 283 * 284 * Several others of our RAID drivers have this check, such as 285 * aac(4) and ida(4), so we insert it here, too. 286 * 287 * The cause of null transfers is yet unknown. 288 */ 289 if (bp->b_bcount == 0) { 290 bp->b_resid = bp->b_bcount; 291 biodone(bio); 292 return (0); 293 } 294 295 bio->bio_driver_info = sc; 296 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 297 mfi_enqueue_bio(controller, bio); 298 devstat_start_transaction(&sc->ld_devstat); 299 mfi_startio(controller); 300 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 301 return (0); 302 } 303 304 void 305 mfi_disk_complete(struct bio *bio) 306 { 307 struct mfi_disk *sc = bio->bio_driver_info; 308 struct buf *bp = bio->bio_buf; 309 310 devstat_end_transaction_buf(&sc->ld_devstat, bp); 311 if (bp->b_flags & B_ERROR) { 312 if (bp->b_error == 0) 313 bp->b_error = EIO; 314 diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1); 315 kprintf("\n"); 316 } else { 317 bp->b_resid = 0; 318 } 319 biodone(bio); 320 } 321 322 static int 323 mfi_disk_dump(struct dev_dump_args *ap) 324 { 325 cdev_t dev = ap->a_head.a_dev; 326 off_t offset = ap->a_offset; 327 void *virt = ap->a_virtual; 328 size_t len = ap->a_length; 329 struct mfi_disk *sc; 330 struct mfi_softc *parent_sc; 331 int error; 332 333 sc = dev->si_drv1; 334 parent_sc = sc->ld_controller; 335 336 if (len > 0) { 337 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 338 MFI_SECTOR_LEN, virt, len)) != 0) 339 return (error); 340 } else { 341 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 342 } 343 344 return (0); 345 } 346