1 /* $NetBSD: ata_raid.c,v 1.5 2003/07/14 15:47:01 lukem 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.5 2003/07/14 15:47:01 lukem Exp $"); 44 45 #include <sys/param.h> 46 #include <sys/buf.h> 47 #include <sys/conf.h> 48 #include <sys/device.h> 49 #include <sys/disk.h> 50 #include <sys/disklabel.h> 51 #include <sys/fcntl.h> 52 #include <sys/malloc.h> 53 #include <sys/vnode.h> 54 55 #include <miscfs/specfs/specdev.h> 56 57 #define __ATA_DISK_PRIVATE 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 68 #ifdef ATA_RAID_DEBUG 69 #define DPRINTF(x) printf x 70 #else 71 #define DPRINTF(x) /* nothing */ 72 #endif 73 74 void ataraidattach(int); 75 76 static int ataraid_match(struct device *, struct cfdata *, void *); 77 static void ataraid_attach(struct device *, struct device *, void *); 78 static int ataraid_print(void *, const char *); 79 80 static int ataraid_submatch(struct device *, struct cfdata *, void *); 81 82 static int ata_raid_finalize(struct device *); 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_DECL(ataraid, sizeof(struct device), 89 ataraid_match, ataraid_attach, NULL, NULL); 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 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 105 printf("WARNING: unable to register ATA RAID finalizer\n"); 106 } 107 108 /* 109 * ata_raid_type_name: 110 * 111 * Return the type of ATA RAID. 112 */ 113 const char * 114 ata_raid_type_name(u_int type) 115 { 116 static const char *ata_raid_type_names[] = { 117 "Promise", 118 }; 119 120 if (type <= ATA_RAID_TYPE_MAX) 121 return (ata_raid_type_names[type]); 122 123 return (NULL); 124 } 125 126 /* 127 * ata_raid_finalize: 128 * 129 * Autoconfiguration finalizer for ATA RAID. 130 */ 131 static int 132 ata_raid_finalize(struct device *self) 133 { 134 extern struct cfdriver ataraid_cd; 135 static int done_once; 136 int error; 137 138 /* 139 * Since we only handle real hardware, we only need to be 140 * called once. 141 */ 142 if (done_once) 143 return (0); 144 done_once = 1; 145 146 if (TAILQ_EMPTY(&ataraid_array_info_list)) 147 goto out; 148 149 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 150 if (error) { 151 printf("%s: unable to register cfattach, error = %d\n", 152 ataraid_cd.cd_name, error); 153 (void) config_cfdriver_detach(&ataraid_cd); 154 goto out; 155 } 156 157 if (config_attach_pseudo(ataraid_cd.cd_name, -1) == NULL) 158 printf("%s: unable to attach an instance\n", 159 ataraid_cd.cd_name); 160 161 out: 162 return (1); 163 } 164 165 /* 166 * ataraid_match: 167 * 168 * Autoconfiguration glue: match routine. 169 */ 170 static int 171 ataraid_match(struct device *parent, struct cfdata *cf, void *aux) 172 { 173 174 /* pseudo-device; always present */ 175 return (1); 176 } 177 178 /* 179 * ataraid_attach: 180 * 181 * Autoconfiguration glue: attach routine. We attach the children. 182 */ 183 static void 184 ataraid_attach(struct device *parent, struct device *self, void *aux) 185 { 186 struct ataraid_array_info *aai; 187 188 /* 189 * We're a pseudo-device, so we get to announce our own 190 * presence. 191 */ 192 aprint_normal("%s: found %u RAID volume%s\n", 193 self->dv_xname, ataraid_array_info_count, 194 ataraid_array_info_count == 1 ? "" : "s"); 195 196 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 197 config_found_sm(self, aai, ataraid_print, ataraid_submatch); 198 } 199 } 200 201 /* 202 * ataraid_print: 203 * 204 * Autoconfiguration glue: print routine. 205 */ 206 static int 207 ataraid_print(void *aux, const char *pnp) 208 { 209 struct ataraid_array_info *aai = aux; 210 211 if (pnp != NULL) 212 aprint_normal("block device at %s", pnp); 213 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 214 return (UNCONF); 215 } 216 217 /* 218 * ataraid_submatch: 219 * 220 * Submatch routine for ATA RAID logical disks. 221 */ 222 static int 223 ataraid_submatch(struct device *parent, struct cfdata *cf, void *aux) 224 { 225 struct ataraid_array_info *aai = aux; 226 227 if (cf->cf_loc[ATARAIDCF_VENDTYPE] != ATARAIDCF_VENDTYPE_DEFAULT && 228 cf->cf_loc[ATARAIDCF_VENDTYPE] != aai->aai_type) 229 return (0); 230 231 if (cf->cf_loc[ATARAIDCF_UNIT] != ATARAIDCF_UNIT_DEFAULT && 232 cf->cf_loc[ATARAIDCF_UNIT] != aai->aai_arrayno) 233 return (0); 234 235 return (config_match(parent, cf, aux)); 236 } 237 238 /* 239 * ata_raid_check_component: 240 * 241 * Check the componet for a RAID configuration structure. 242 * Called via autoconfiguration callback. 243 */ 244 void 245 ata_raid_check_component(struct device *self) 246 { 247 struct wd_softc *sc = (void *) self; 248 249 if (ata_raid_read_config_promise(sc) == 0) 250 return; 251 } 252 253 struct ataraid_array_info * 254 ata_raid_get_array_info(u_int type, u_int arrayno) 255 { 256 struct ataraid_array_info *aai, *laai; 257 258 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 259 if (aai->aai_type == type && 260 aai->aai_arrayno == arrayno) 261 goto out; 262 } 263 264 /* Need to allocate a new one. */ 265 aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); 266 aai->aai_type = type; 267 aai->aai_arrayno = arrayno; 268 269 ataraid_array_info_count++; 270 271 if (TAILQ_EMPTY(&ataraid_array_info_list)) { 272 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 273 goto out; 274 } 275 276 /* Sort it into the list: type first, then array number. */ 277 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 278 if (aai->aai_type < laai->aai_type) { 279 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 280 goto out; 281 } 282 if (aai->aai_type == laai->aai_type && 283 aai->aai_arrayno < laai->aai_arrayno) { 284 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 285 goto out; 286 } 287 } 288 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 289 290 out: 291 return (aai); 292 } 293 294 int 295 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *buf, 296 size_t size, int bflags) 297 { 298 struct buf *bp; 299 int error, s; 300 301 s = splbio(); 302 bp = pool_get(&bufpool, PR_WAITOK); 303 splx(s); 304 BUF_INIT(bp); 305 306 bp->b_vp = vp; 307 bp->b_dev = vp->v_rdev; 308 bp->b_blkno = blkno; 309 bp->b_bcount = bp->b_resid = size; 310 bp->b_flags = bflags; 311 bp->b_proc = curproc; 312 bp->b_data = buf; 313 314 VOP_STRATEGY(bp); 315 error = biowait(bp); 316 317 s = splbio(); 318 pool_put(&bufpool, bp); 319 splx(s); 320 return (error); 321 } 322