1 /* $NetBSD: ata_raid.c,v 1.41 2018/10/22 19:38:06 jdolecek 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.41 2018/10/22 19:38:06 jdolecek 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/vnode.h> 54 #include <sys/proc.h> 55 #include <sys/module.h> 56 57 #include <miscfs/specfs/specdev.h> 58 59 #include <dev/ata/atareg.h> 60 #include <dev/ata/atavar.h> 61 #include <dev/ata/wdvar.h> 62 63 #include <dev/ata/ata_raidreg.h> 64 #include <dev/ata/ata_raidvar.h> 65 66 #include "locators.h" 67 #include "ioconf.h" 68 69 #ifdef ATA_RAID_DEBUG 70 #define DPRINTF(x) printf x 71 #else 72 #define DPRINTF(x) /* nothing */ 73 #endif 74 75 static int ataraid_match(device_t, cfdata_t, void *); 76 static void ataraid_attach(device_t, device_t, void *); 77 static int ataraid_rescan(device_t, const char *, const int *); 78 static int ataraid_print(void *, const char *); 79 80 static int ata_raid_finalize(device_t); 81 82 static int finalize_done; 83 84 ataraid_array_info_list_t ataraid_array_info_list = 85 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 86 u_int ataraid_array_info_count; 87 88 CFATTACH_DECL3_NEW(ataraid, 0, 89 ataraid_match, ataraid_attach, NULL, NULL, ataraid_rescan, NULL, 0); 90 91 /* 92 * ataraidattach: 93 * 94 * Pseudo-device attach routine. 95 */ 96 void 97 ataraidattach(int count) 98 { 99 100 /* 101 * Register a finalizer which will be used to actually configure 102 * the logical disks configured by ataraid. 103 */ 104 finalize_done = 0; 105 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 106 aprint_normal("WARNING: " 107 "unable to register ATA RAID finalizer\n"); 108 } 109 110 /* 111 * Use the config_finalizer to rescan for new devices, since the 112 * ld_ataraid driver might not be immediately available. 113 */ 114 115 /* ARGSUSED */ 116 static int 117 ataraid_rescan(device_t self, const char *attr, const int *flags) 118 { 119 120 finalize_done = 0; 121 (void)ata_raid_finalize(self); 122 123 return 0; 124 } 125 126 /* 127 * ata_raid_type_name: 128 * 129 * Return the type of ATA RAID. 130 */ 131 const char * 132 ata_raid_type_name(u_int type) 133 { 134 static const char *ata_raid_type_names[] = { 135 "Promise", 136 "Adaptec", 137 "VIA V-RAID", 138 "nVidia", 139 "JMicron", 140 "Intel MatrixRAID" 141 }; 142 143 if (type < __arraycount(ata_raid_type_names)) 144 return (ata_raid_type_names[type]); 145 146 return (NULL); 147 } 148 149 /* 150 * ata_raid_finalize: 151 * 152 * Autoconfiguration finalizer for ATA RAID. 153 */ 154 static int 155 ata_raid_finalize(device_t self) 156 { 157 static struct cfdata ataraid_cfdata = { 158 .cf_name = "ataraid", 159 .cf_atname = "ataraid", 160 .cf_unit = 0, 161 .cf_fstate = FSTATE_STAR, 162 }; 163 164 /* 165 * Only run once for each instantiation 166 */ 167 if (finalize_done) 168 return 0; 169 finalize_done = 1; 170 171 if (TAILQ_EMPTY(&ataraid_array_info_list)) 172 goto out; 173 174 if (config_attach_pseudo(&ataraid_cfdata) == NULL) 175 printf("%s: unable to attach an instance\n", 176 ataraid_cd.cd_name); 177 178 out: 179 return (1); 180 } 181 182 /* 183 * ataraid_match: 184 * 185 * Autoconfiguration glue: match routine. 186 */ 187 static int 188 ataraid_match(device_t parent, cfdata_t cf, void *aux) 189 { 190 191 /* pseudo-device; always present */ 192 return (1); 193 } 194 195 /* 196 * ataraid_attach: 197 * 198 * Autoconfiguration glue: attach routine. We attach the children. 199 */ 200 static void 201 ataraid_attach(device_t parent, device_t self, void *aux) 202 { 203 struct ataraid_array_info *aai; 204 int locs[ATARAIDCF_NLOCS]; 205 206 /* 207 * We're a pseudo-device, so we get to announce our own 208 * presence. 209 */ 210 aprint_normal_dev(self, "found %u RAID volume%s\n", 211 ataraid_array_info_count, 212 ataraid_array_info_count == 1 ? "" : "s"); 213 214 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 215 locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 216 locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 217 218 config_found_sm_loc(self, "ataraid", locs, aai, 219 ataraid_print, config_stdsubmatch); 220 } 221 } 222 223 /* 224 * ataraid_print: 225 * 226 * Autoconfiguration glue: print routine. 227 */ 228 static int 229 ataraid_print(void *aux, const char *pnp) 230 { 231 struct ataraid_array_info *aai = aux; 232 233 if (pnp != NULL) 234 aprint_normal("block device at %s", pnp); 235 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 236 return (UNCONF); 237 } 238 239 /* 240 * ata_raid_check_component: 241 * 242 * Check the component for a RAID configuration structure. 243 * Called via autoconfiguration callback. 244 */ 245 void 246 ata_raid_check_component(device_t self) 247 { 248 struct wd_softc *sc = device_private(self); 249 250 if (ata_raid_read_config_adaptec(sc) == 0) 251 return; 252 if (ata_raid_read_config_promise(sc) == 0) 253 return; 254 if (ata_raid_read_config_via(sc) == 0) 255 return; 256 if (ata_raid_read_config_nvidia(sc) == 0) 257 return; 258 if (ata_raid_read_config_jmicron(sc) == 0) 259 return; 260 if (ata_raid_read_config_intel(sc) == 0) 261 return; 262 } 263 264 struct ataraid_array_info * 265 ata_raid_get_array_info(u_int type, u_int arrayno) 266 { 267 struct ataraid_array_info *aai, *laai; 268 269 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 270 if (aai->aai_type == type && 271 aai->aai_arrayno == arrayno) 272 goto out; 273 } 274 275 /* Need to allocate a new one. */ 276 aai = kmem_zalloc(sizeof(*aai), KM_SLEEP); 277 aai->aai_type = type; 278 aai->aai_arrayno = arrayno; 279 aai->aai_curdisk = 0; 280 281 ataraid_array_info_count++; 282 283 /* Sort it into the list: type first, then array number. */ 284 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 285 if (aai->aai_type < laai->aai_type) { 286 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 287 goto out; 288 } 289 if (aai->aai_type == laai->aai_type && 290 aai->aai_arrayno < laai->aai_arrayno) { 291 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 292 goto out; 293 } 294 } 295 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 296 297 out: 298 return (aai); 299 } 300 301 int 302 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, 303 size_t size, int bflags) 304 { 305 struct buf *bp; 306 int error; 307 308 bp = getiobuf(vp, false); 309 bp->b_blkno = blkno; 310 bp->b_bcount = bp->b_resid = size; 311 bp->b_flags = bflags; 312 bp->b_proc = curproc; 313 bp->b_data = tbuf; 314 SET(bp->b_cflags, BC_BUSY); /* mark buffer busy */ 315 316 VOP_STRATEGY(vp, bp); 317 error = biowait(bp); 318 319 putiobuf(bp); 320 return (error); 321 } 322 323 MODULE(MODULE_CLASS_DRIVER, ataraid, ""); 324 325 #ifdef _MODULE 326 CFDRIVER_DECL(ataraid, DV_DISK, NULL); 327 #endif 328 329 static int 330 ataraid_modcmd(modcmd_t cmd, void *arg) 331 { 332 int error = 0; 333 334 switch (cmd) { 335 case MODULE_CMD_INIT: 336 #ifdef _MODULE 337 error = config_cfdriver_attach(&ataraid_cd); 338 if (error) 339 break; 340 #endif 341 342 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 343 if (error) { 344 #ifdef _MODULE 345 config_cfdriver_detach(&ataraid_cd); 346 #endif 347 aprint_error("%s: unable to register cfattach for \n" 348 "%s, error %d", __func__, ataraid_cd.cd_name, 349 error); 350 break; 351 } 352 break; 353 case MODULE_CMD_FINI: 354 error = config_cfattach_detach(ataraid_cd.cd_name, &ataraid_ca); 355 if (error) { 356 aprint_error("%s: failed to detach %s cfattach, " 357 "error %d\n", __func__, ataraid_cd.cd_name, error); 358 break; 359 } 360 #ifdef _MODULE 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