1 /* $NetBSD: ata_raid.c,v 1.39 2016/09/27 08:05:34 pgoyette Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 /* 39 * Support for autoconfiguration of RAID sets on ATA RAID controllers. 40 */ 41 42 #include <sys/cdefs.h> 43 __KERNEL_RCSID(0, "$NetBSD: ata_raid.c,v 1.39 2016/09/27 08:05:34 pgoyette Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/buf.h> 47 #include <sys/bufq.h> 48 #include <sys/conf.h> 49 #include <sys/device.h> 50 #include <sys/disk.h> 51 #include <sys/disklabel.h> 52 #include <sys/fcntl.h> 53 #include <sys/malloc.h> 54 #include <sys/vnode.h> 55 #include <sys/proc.h> 56 #include <sys/module.h> 57 58 #include <miscfs/specfs/specdev.h> 59 60 #include <dev/ata/atareg.h> 61 #include <dev/ata/atavar.h> 62 #include <dev/ata/wdvar.h> 63 64 #include <dev/ata/ata_raidreg.h> 65 #include <dev/ata/ata_raidvar.h> 66 67 #include "locators.h" 68 #include "ioconf.h" 69 70 #ifdef ATA_RAID_DEBUG 71 #define DPRINTF(x) printf x 72 #else 73 #define DPRINTF(x) /* nothing */ 74 #endif 75 76 static int ataraid_match(device_t, cfdata_t, void *); 77 static void ataraid_attach(device_t, device_t, void *); 78 static int ataraid_rescan(device_t, const char *, const int *); 79 static int ataraid_print(void *, const char *); 80 81 static int ata_raid_finalize(device_t); 82 83 static int finalize_done; 84 85 ataraid_array_info_list_t ataraid_array_info_list = 86 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 87 u_int ataraid_array_info_count; 88 89 CFATTACH_DECL3_NEW(ataraid, 0, 90 ataraid_match, ataraid_attach, NULL, NULL, ataraid_rescan, NULL, 0); 91 92 /* 93 * ataraidattach: 94 * 95 * Pseudo-device attach routine. 96 */ 97 void 98 ataraidattach(int count) 99 { 100 101 /* 102 * Register a finalizer which will be used to actually configure 103 * the logical disks configured by ataraid. 104 */ 105 finalize_done = 0; 106 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 107 aprint_normal("WARNING: " 108 "unable to register ATA RAID finalizer\n"); 109 } 110 111 /* 112 * Use the config_finalizer to rescan for new devices, since the 113 * ld_ataraid driver might not be immediately available. 114 */ 115 116 /* ARGSUSED */ 117 static int 118 ataraid_rescan(device_t self, const char *attr, const int *flags) 119 { 120 121 finalize_done = 0; 122 (void)ata_raid_finalize(self); 123 124 return 0; 125 } 126 127 /* 128 * ata_raid_type_name: 129 * 130 * Return the type of ATA RAID. 131 */ 132 const char * 133 ata_raid_type_name(u_int type) 134 { 135 static const char *ata_raid_type_names[] = { 136 "Promise", 137 "Adaptec", 138 "VIA V-RAID", 139 "nVidia", 140 "JMicron", 141 "Intel MatrixRAID" 142 }; 143 144 if (type < __arraycount(ata_raid_type_names)) 145 return (ata_raid_type_names[type]); 146 147 return (NULL); 148 } 149 150 /* 151 * ata_raid_finalize: 152 * 153 * Autoconfiguration finalizer for ATA RAID. 154 */ 155 static int 156 ata_raid_finalize(device_t self) 157 { 158 static struct cfdata ataraid_cfdata = { 159 .cf_name = "ataraid", 160 .cf_atname = "ataraid", 161 .cf_unit = 0, 162 .cf_fstate = FSTATE_STAR, 163 }; 164 165 /* 166 * Only run once for each instantiation 167 */ 168 if (finalize_done) 169 return 0; 170 finalize_done = 1; 171 172 if (TAILQ_EMPTY(&ataraid_array_info_list)) 173 goto out; 174 175 if (config_attach_pseudo(&ataraid_cfdata) == NULL) 176 printf("%s: unable to attach an instance\n", 177 ataraid_cd.cd_name); 178 179 out: 180 return (1); 181 } 182 183 /* 184 * ataraid_match: 185 * 186 * Autoconfiguration glue: match routine. 187 */ 188 static int 189 ataraid_match(device_t parent, cfdata_t cf, void *aux) 190 { 191 192 /* pseudo-device; always present */ 193 return (1); 194 } 195 196 /* 197 * ataraid_attach: 198 * 199 * Autoconfiguration glue: attach routine. We attach the children. 200 */ 201 static void 202 ataraid_attach(device_t parent, device_t self, void *aux) 203 { 204 struct ataraid_array_info *aai; 205 int locs[ATARAIDCF_NLOCS]; 206 207 /* 208 * We're a pseudo-device, so we get to announce our own 209 * presence. 210 */ 211 aprint_normal_dev(self, "found %u RAID volume%s\n", 212 ataraid_array_info_count, 213 ataraid_array_info_count == 1 ? "" : "s"); 214 215 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 216 locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 217 locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 218 219 config_found_sm_loc(self, "ataraid", locs, aai, 220 ataraid_print, config_stdsubmatch); 221 } 222 } 223 224 /* 225 * ataraid_print: 226 * 227 * Autoconfiguration glue: print routine. 228 */ 229 static int 230 ataraid_print(void *aux, const char *pnp) 231 { 232 struct ataraid_array_info *aai = aux; 233 234 if (pnp != NULL) 235 aprint_normal("block device at %s", pnp); 236 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 237 return (UNCONF); 238 } 239 240 /* 241 * ata_raid_check_component: 242 * 243 * Check the component for a RAID configuration structure. 244 * Called via autoconfiguration callback. 245 */ 246 void 247 ata_raid_check_component(device_t self) 248 { 249 struct wd_softc *sc = device_private(self); 250 251 if (ata_raid_read_config_adaptec(sc) == 0) 252 return; 253 if (ata_raid_read_config_promise(sc) == 0) 254 return; 255 if (ata_raid_read_config_via(sc) == 0) 256 return; 257 if (ata_raid_read_config_nvidia(sc) == 0) 258 return; 259 if (ata_raid_read_config_jmicron(sc) == 0) 260 return; 261 if (ata_raid_read_config_intel(sc) == 0) 262 return; 263 } 264 265 struct ataraid_array_info * 266 ata_raid_get_array_info(u_int type, u_int arrayno) 267 { 268 struct ataraid_array_info *aai, *laai; 269 270 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 271 if (aai->aai_type == type && 272 aai->aai_arrayno == arrayno) 273 goto out; 274 } 275 276 /* Need to allocate a new one. */ 277 aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); 278 aai->aai_type = type; 279 aai->aai_arrayno = arrayno; 280 aai->aai_curdisk = 0; 281 282 ataraid_array_info_count++; 283 284 /* Sort it into the list: type first, then array number. */ 285 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 286 if (aai->aai_type < laai->aai_type) { 287 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 288 goto out; 289 } 290 if (aai->aai_type == laai->aai_type && 291 aai->aai_arrayno < laai->aai_arrayno) { 292 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 293 goto out; 294 } 295 } 296 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 297 298 out: 299 return (aai); 300 } 301 302 int 303 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, 304 size_t size, int bflags) 305 { 306 struct buf *bp; 307 int error; 308 309 bp = getiobuf(vp, false); 310 bp->b_blkno = blkno; 311 bp->b_bcount = bp->b_resid = size; 312 bp->b_flags = bflags; 313 bp->b_proc = curproc; 314 bp->b_data = tbuf; 315 SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ 316 317 VOP_STRATEGY(vp, bp); 318 error = biowait(bp); 319 320 putiobuf(bp); 321 return (error); 322 } 323 324 MODULE(MODULE_CLASS_DRIVER, ataraid, ""); 325 326 #ifdef _MODULE 327 CFDRIVER_DECL(ataraid, DV_DISK, NULL); 328 #endif 329 330 static int 331 ataraid_modcmd(modcmd_t cmd, void *arg) 332 { 333 int error = 0; 334 335 switch (cmd) { 336 case MODULE_CMD_INIT: 337 #ifdef _MODULE 338 error = config_cfdriver_attach(&ataraid_cd); 339 if (error) 340 break; 341 342 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 343 if (error) { 344 config_cfdriver_detach(&ataraid_cd); 345 aprint_error("%s: unable to register cfattach for \n" 346 "%s, error %d", __func__, ataraid_cd.cd_name, 347 error); 348 break; 349 } 350 #endif 351 break; 352 case MODULE_CMD_FINI: 353 #ifdef _MODULE 354 355 error = config_cfattach_detach(ataraid_cd.cd_name, &ataraid_ca); 356 if (error) { 357 aprint_error("%s: failed to detach %s cfattach, " 358 "error %d\n", __func__, ataraid_cd.cd_name, error); 359 break; 360 } 361 error = config_cfdriver_detach(&ataraid_cd); 362 if (error) { 363 (void)config_cfattach_attach(ataraid_cd.cd_name, 364 &ataraid_ca); 365 aprint_error("%s: failed to detach %s cfdriver, " 366 "error %d\n", __func__, ataraid_cd.cd_name, error); 367 break; 368 } 369 #endif 370 break; 371 case MODULE_CMD_STAT: 372 default: 373 error = ENOTTY; 374 } 375 376 return error; 377 } 378