1 /*- 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that the following conditions 4 * are met: 5 * 6 * Copyright 1994-2009 The FreeBSD Project. 7 * All rights reserved. 8 * 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 FREEBSD PROJECT``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY,OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 * 27 * The views and conclusions contained in the software and documentation 28 * are those of the authors and should not be interpreted as representing 29 * official policies,either expressed or implied, of the FreeBSD Project. 30 * 31 * $FreeBSD: src/sys/dev/mfi/mfi_pddisk.c,v 1.2.2.6 2007/08/24 17:29:18 jhb Exp $ 32 * FreeBSD projects/head_mfi/ r232888 33 */ 34 35 #include "opt_mfi.h" 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/module.h> 41 #include <sys/malloc.h> 42 #include <sys/uio.h> 43 44 #include <sys/bio.h> 45 #include <sys/buf2.h> 46 #include <sys/bus.h> 47 #include <sys/conf.h> 48 #include <sys/disk.h> 49 50 #include <vm/vm.h> 51 #include <vm/pmap.h> 52 53 #include <machine/md_var.h> 54 #include <sys/rman.h> 55 56 #include <dev/raid/mfi/mfireg.h> 57 #include <dev/raid/mfi/mfi_ioctl.h> 58 #include <dev/raid/mfi/mfivar.h> 59 60 static int mfi_syspd_probe(device_t dev); 61 static int mfi_syspd_attach(device_t dev); 62 static int mfi_syspd_detach(device_t dev); 63 64 static d_open_t mfi_syspd_open; 65 static d_close_t mfi_syspd_close; 66 static d_strategy_t mfi_syspd_strategy; 67 static d_dump_t mfi_syspd_dump; 68 69 static struct dev_ops mfi_syspd_ops = { 70 { "mfisyspd", 0, D_DISK }, 71 .d_open = mfi_syspd_open, 72 .d_close = mfi_syspd_close, 73 .d_strategy = mfi_syspd_strategy, 74 .d_dump = mfi_syspd_dump, 75 }; 76 77 static devclass_t mfi_syspd_devclass; 78 79 static device_method_t mfi_syspd_methods[] = { 80 DEVMETHOD(device_probe, mfi_syspd_probe), 81 DEVMETHOD(device_attach, mfi_syspd_attach), 82 DEVMETHOD(device_detach, mfi_syspd_detach), 83 { 0, 0 } 84 }; 85 86 static driver_t mfi_syspd_driver = { 87 "mfisyspd", 88 mfi_syspd_methods, 89 sizeof(struct mfi_system_pd) 90 }; 91 92 DRIVER_MODULE(mfisyspd, mfi, mfi_syspd_driver, mfi_syspd_devclass, NULL, NULL); 93 94 static int 95 mfi_syspd_probe(device_t dev) 96 { 97 98 return (0); 99 } 100 101 static int 102 mfi_syspd_attach(device_t dev) 103 { 104 struct mfi_system_pd *sc; 105 struct mfi_pd_info *pd_info; 106 struct disk_info info; 107 uint64_t sectors; 108 uint32_t secsize; 109 110 sc = device_get_softc(dev); 111 pd_info = device_get_ivars(dev); 112 113 sc->pd_dev = dev; 114 sc->pd_id = pd_info->ref.v.device_id; 115 sc->pd_unit = device_get_unit(dev); 116 sc->pd_info = pd_info; 117 sc->pd_controller = device_get_softc(device_get_parent(dev)); 118 sc->pd_flags = MFI_DISK_FLAGS_SYSPD; 119 120 sectors = pd_info->raw_size; 121 secsize = MFI_SECTOR_LEN; 122 lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); 123 TAILQ_INSERT_TAIL(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link); 124 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 125 device_printf(dev, "%juMB (%ju sectors) SYSPD volume\n", 126 sectors / (1024 * 1024 / secsize), sectors); 127 128 devstat_add_entry(&sc->pd_devstat, "mfisyspd", device_get_unit(dev), 129 MFI_SECTOR_LEN, DEVSTAT_NO_ORDERED_TAGS, 130 DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER, 131 DEVSTAT_PRIORITY_ARRAY); 132 133 sc->pd_dev_t = disk_create(sc->pd_unit, &sc->pd_disk, &mfi_syspd_ops); 134 sc->pd_dev_t->si_drv1 = sc; 135 sc->pd_dev_t->si_iosize_max = sc->pd_controller->mfi_max_io * 136 secsize; 137 138 bzero(&info, sizeof(info)); 139 info.d_media_blksize = secsize; /* mandatory */ 140 info.d_media_blocks = sectors; 141 142 if (info.d_media_blocks >= (1 * 1024 * 1024)) { 143 info.d_nheads = 255; 144 info.d_secpertrack = 63; 145 } else { 146 info.d_nheads = 64; 147 info.d_secpertrack = 32; 148 } 149 150 disk_setdiskinfo(&sc->pd_disk, &info); 151 152 return (0); 153 } 154 155 static int 156 mfi_syspd_detach(device_t dev) 157 { 158 struct mfi_system_pd *sc; 159 160 sc = device_get_softc(dev); 161 lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); 162 if ((sc->pd_flags & MFI_DISK_FLAGS_OPEN) && 163 (sc->pd_controller->mfi_keep_deleted_volumes || 164 sc->pd_controller->mfi_detaching)) { 165 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 166 return (EBUSY); 167 } 168 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 169 170 disk_destroy(&sc->pd_disk); 171 devstat_remove_entry(&sc->pd_devstat); 172 lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); 173 TAILQ_REMOVE(&sc->pd_controller->mfi_syspd_tqh, sc, pd_link); 174 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 175 kfree(sc->pd_info, M_MFIBUF); 176 return (0); 177 } 178 179 static int 180 mfi_syspd_open(struct dev_open_args *ap) 181 { 182 struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; 183 int error; 184 185 lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); 186 if (sc->pd_flags & MFI_DISK_FLAGS_DISABLED) 187 error = ENXIO; 188 else { 189 sc->pd_flags |= MFI_DISK_FLAGS_OPEN; 190 error = 0; 191 } 192 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 193 return (error); 194 } 195 196 static int 197 mfi_syspd_close(struct dev_close_args *ap) 198 { 199 struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; 200 201 lockmgr(&sc->pd_controller->mfi_io_lock, LK_EXCLUSIVE); 202 sc->pd_flags &= ~MFI_DISK_FLAGS_OPEN; 203 lockmgr(&sc->pd_controller->mfi_io_lock, LK_RELEASE); 204 205 return (0); 206 } 207 208 int 209 mfi_syspd_disable(struct mfi_system_pd *sc) 210 { 211 212 mfi_lockassert(&sc->pd_controller->mfi_io_lock); 213 if (sc->pd_flags & MFI_DISK_FLAGS_OPEN) { 214 if (sc->pd_controller->mfi_delete_busy_volumes) 215 return (0); 216 device_printf(sc->pd_dev, 217 "Unable to delete busy syspd device\n"); 218 return (EBUSY); 219 } 220 sc->pd_flags |= MFI_DISK_FLAGS_DISABLED; 221 return (0); 222 } 223 224 void 225 mfi_syspd_enable(struct mfi_system_pd *sc) 226 { 227 228 mfi_lockassert(&sc->pd_controller->mfi_io_lock); 229 sc->pd_flags &= ~MFI_DISK_FLAGS_DISABLED; 230 } 231 232 static int 233 mfi_syspd_strategy(struct dev_strategy_args *ap) 234 { 235 struct bio *bio = ap->a_bio; 236 struct buf *bp = bio->bio_buf; 237 struct mfi_system_pd *sc = ap->a_head.a_dev->si_drv1; 238 struct mfi_softc *controller = sc->pd_controller; 239 240 if (sc == NULL) { 241 bp->b_error = EINVAL; 242 bp->b_flags |= B_ERROR; 243 bp->b_resid = bp->b_bcount; 244 biodone(bio); 245 return (0); 246 } 247 248 if (controller->hw_crit_error) { 249 bp->b_error = EBUSY; 250 return (0); 251 } 252 253 if (controller->issuepend_done == 0) { 254 bp->b_error = EBUSY; 255 return (0); 256 } 257 258 /* 259 * XXX swildner 260 * 261 * If it's a null transfer, do nothing. FreeBSD's original driver 262 * doesn't have this, but that caused hard error messages (even 263 * though everything else continued to work fine). Interestingly, 264 * only when HAMMER was used. 265 * 266 * Several others of our RAID drivers have this check, such as 267 * aac(4) and ida(4), so we insert it here, too. 268 * 269 * The cause of null transfers is yet unknown. 270 */ 271 if (bp->b_bcount == 0) { 272 bp->b_resid = bp->b_bcount; 273 biodone(bio); 274 return (0); 275 } 276 277 bio->bio_driver_info = sc; 278 lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE); 279 mfi_enqueue_bio(controller, bio); 280 devstat_start_transaction(&sc->pd_devstat); 281 mfi_startio(controller); 282 lockmgr(&controller->mfi_io_lock, LK_RELEASE); 283 return (0); 284 } 285 286 static int 287 mfi_syspd_dump(struct dev_dump_args *ap) 288 { 289 cdev_t dev = ap->a_head.a_dev; 290 off_t offset = ap->a_offset; 291 void *virt = ap->a_virtual; 292 size_t len = ap->a_length; 293 struct mfi_system_pd *sc; 294 struct mfi_softc *parent_sc; 295 int error; 296 297 sc = dev->si_drv1; 298 parent_sc = sc->pd_controller; 299 300 if (len > 0) { 301 if ((error = mfi_dump_syspd_blocks(parent_sc, 302 sc->pd_id, offset / MFI_SECTOR_LEN, virt, len)) != 0) 303 return (error); 304 } else { 305 /* mfi_sync_cache(parent_sc, sc->ld_id); */ 306 } 307 return (0); 308 } 309