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 }, 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 { 0, 0 } 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 = sc->ld_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 if (controller->hw_crit_error) { 266 bp->b_error = EBUSY; 267 return (0); 268 } 269 270 if (controller->issuepend_done == 0) { 271 bp->b_error = EBUSY; 272 return (0); 273 } 274 275 /* 276 * XXX swildner 277 * 278 * If it's a null transfer, do nothing. FreeBSD's original driver 279 * doesn't have this, but that caused hard error messages (even 280 * though everything else continued to work fine). Interestingly, 281 * only when HAMMER was used. 282 * 283 * Several others of our RAID drivers have this check, such as 284 * aac(4) and ida(4), so we insert it here, too. 285 * 286 * The cause of null transfers is yet unknown. 287 */ 288 if (bp->b_bcount == 0) { 289 bp->b_resid = bp->b_bcount; 290 biodone(bio); 291 return (0); 292 } 293 294 bio->bio_driver_info = sc; 295 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 296 mfi_enqueue_bio(controller, bio); 297 devstat_start_transaction(&sc->ld_devstat); 298 mfi_startio(controller); 299 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 300 return (0); 301 } 302 303 void 304 mfi_disk_complete(struct bio *bio) 305 { 306 struct mfi_disk *sc = bio->bio_driver_info; 307 struct buf *bp = bio->bio_buf; 308 309 devstat_end_transaction_buf(&sc->ld_devstat, bp); 310 if (bp->b_flags & B_ERROR) { 311 if (bp->b_error == 0) 312 bp->b_error = EIO; 313 diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1); 314 kprintf("\n"); 315 } else { 316 bp->b_resid = 0; 317 } 318 biodone(bio); 319 } 320 321 static int 322 mfi_disk_dump(struct dev_dump_args *ap) 323 { 324 cdev_t dev = ap->a_head.a_dev; 325 off_t offset = ap->a_offset; 326 void *virt = ap->a_virtual; 327 size_t len = ap->a_length; 328 struct mfi_disk *sc; 329 struct mfi_softc *parent_sc; 330 int error; 331 332 sc = dev->si_drv1; 333 parent_sc = sc->ld_controller; 334 335 if (len > 0) { 336 if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset / 337 MFI_SECTOR_LEN, virt, len)) != 0) 338 return (error); 339 } else { 340 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 341 } 342 343 return (0); 344 } 345