1 /* $NetBSD: ata_raid.c,v 1.19 2006/10/12 01:30:55 christos 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.19 2006/10/12 01:30:55 christos 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 56 #include <miscfs/specfs/specdev.h> 57 58 #include <dev/ata/atareg.h> 59 #include <dev/ata/atavar.h> 60 #include <dev/ata/wdvar.h> 61 62 #include <dev/ata/ata_raidreg.h> 63 #include <dev/ata/ata_raidvar.h> 64 65 #include "locators.h" 66 67 #ifdef ATA_RAID_DEBUG 68 #define DPRINTF(x) printf x 69 #else 70 #define DPRINTF(x) /* nothing */ 71 #endif 72 73 void ataraidattach(int); 74 75 static int ataraid_match(struct device *, struct cfdata *, void *); 76 static void ataraid_attach(struct device *, struct device *, void *); 77 static int ataraid_print(void *, const char *); 78 79 static int ata_raid_finalize(struct device *); 80 81 ataraid_array_info_list_t ataraid_array_info_list = 82 TAILQ_HEAD_INITIALIZER(ataraid_array_info_list); 83 u_int ataraid_array_info_count; 84 85 CFATTACH_DECL(ataraid, sizeof(struct device), 86 ataraid_match, ataraid_attach, NULL, NULL); 87 88 /* 89 * ataraidattach: 90 * 91 * Pseudo-device attach routine. 92 */ 93 void 94 ataraidattach(int count __unused) 95 { 96 97 /* 98 * Register a finalizer which will be used to actually configure 99 * the logical disks configured by ataraid. 100 */ 101 if (config_finalize_register(NULL, ata_raid_finalize) != 0) 102 printf("WARNING: unable to register ATA RAID finalizer\n"); 103 } 104 105 /* 106 * ata_raid_type_name: 107 * 108 * Return the type of ATA RAID. 109 */ 110 const char * 111 ata_raid_type_name(u_int type) 112 { 113 static const char *ata_raid_type_names[] = { 114 "Promise", 115 "Adaptec", 116 }; 117 118 if (type < sizeof(ata_raid_type_names) / sizeof(ata_raid_type_names[0])) 119 return (ata_raid_type_names[type]); 120 121 return (NULL); 122 } 123 124 /* 125 * ata_raid_finalize: 126 * 127 * Autoconfiguration finalizer for ATA RAID. 128 */ 129 static int 130 ata_raid_finalize(struct device *self __unused) 131 { 132 static struct cfdata ataraid_cfdata = { 133 .cf_name = "ataraid", 134 .cf_atname = "ataraid", 135 .cf_unit = DVUNIT_ANY, 136 .cf_fstate = FSTATE_STAR, 137 }; 138 extern struct cfdriver ataraid_cd; 139 static int done_once; 140 int error; 141 142 /* 143 * Since we only handle real hardware, we only need to be 144 * called once. 145 */ 146 if (done_once) 147 return (0); 148 done_once = 1; 149 150 if (TAILQ_EMPTY(&ataraid_array_info_list)) 151 goto out; 152 153 error = config_cfattach_attach(ataraid_cd.cd_name, &ataraid_ca); 154 if (error) { 155 printf("%s: unable to register cfattach, error = %d\n", 156 ataraid_cd.cd_name, error); 157 (void) config_cfdriver_detach(&ataraid_cd); 158 goto out; 159 } 160 161 if (config_attach_pseudo(&ataraid_cfdata) == NULL) 162 printf("%s: unable to attach an instance\n", 163 ataraid_cd.cd_name); 164 165 out: 166 return (1); 167 } 168 169 /* 170 * ataraid_match: 171 * 172 * Autoconfiguration glue: match routine. 173 */ 174 static int 175 ataraid_match(struct device *parent __unused, struct cfdata *cf __unused, 176 void *aux __unused) 177 { 178 179 /* pseudo-device; always present */ 180 return (1); 181 } 182 183 /* 184 * ataraid_attach: 185 * 186 * Autoconfiguration glue: attach routine. We attach the children. 187 */ 188 static void 189 ataraid_attach(struct device *parent __unused, struct device *self, 190 void *aux __unused) 191 { 192 struct ataraid_array_info *aai; 193 int locs[ATARAIDCF_NLOCS]; 194 195 /* 196 * We're a pseudo-device, so we get to announce our own 197 * presence. 198 */ 199 aprint_normal("%s: found %u RAID volume%s\n", 200 self->dv_xname, ataraid_array_info_count, 201 ataraid_array_info_count == 1 ? "" : "s"); 202 203 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 204 locs[ATARAIDCF_VENDTYPE] = aai->aai_type; 205 locs[ATARAIDCF_UNIT] = aai->aai_arrayno; 206 207 config_found_sm_loc(self, "ataraid", locs, aai, 208 ataraid_print, config_stdsubmatch); 209 } 210 } 211 212 /* 213 * ataraid_print: 214 * 215 * Autoconfiguration glue: print routine. 216 */ 217 static int 218 ataraid_print(void *aux, const char *pnp) 219 { 220 struct ataraid_array_info *aai = aux; 221 222 if (pnp != NULL) 223 aprint_normal("block device at %s", pnp); 224 aprint_normal(" vendtype %d unit %d", aai->aai_type, aai->aai_arrayno); 225 return (UNCONF); 226 } 227 228 /* 229 * ata_raid_check_component: 230 * 231 * Check the component for a RAID configuration structure. 232 * Called via autoconfiguration callback. 233 */ 234 void 235 ata_raid_check_component(struct device *self) 236 { 237 struct wd_softc *sc = (void *) self; 238 239 if (ata_raid_read_config_adaptec(sc) == 0) 240 return; 241 if (ata_raid_read_config_promise(sc) == 0) 242 return; 243 } 244 245 struct ataraid_array_info * 246 ata_raid_get_array_info(u_int type, u_int arrayno) 247 { 248 struct ataraid_array_info *aai, *laai; 249 250 TAILQ_FOREACH(aai, &ataraid_array_info_list, aai_list) { 251 if (aai->aai_type == type && 252 aai->aai_arrayno == arrayno) 253 goto out; 254 } 255 256 /* Need to allocate a new one. */ 257 aai = malloc(sizeof(*aai), M_DEVBUF, M_WAITOK | M_ZERO); 258 aai->aai_type = type; 259 aai->aai_arrayno = arrayno; 260 261 ataraid_array_info_count++; 262 263 if (TAILQ_EMPTY(&ataraid_array_info_list)) { 264 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 265 goto out; 266 } 267 268 /* Sort it into the list: type first, then array number. */ 269 TAILQ_FOREACH(laai, &ataraid_array_info_list, aai_list) { 270 if (aai->aai_type < laai->aai_type) { 271 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 272 goto out; 273 } 274 if (aai->aai_type == laai->aai_type && 275 aai->aai_arrayno < laai->aai_arrayno) { 276 TAILQ_INSERT_BEFORE(laai, aai, aai_list); 277 goto out; 278 } 279 } 280 TAILQ_INSERT_TAIL(&ataraid_array_info_list, aai, aai_list); 281 282 out: 283 return (aai); 284 } 285 286 int 287 ata_raid_config_block_rw(struct vnode *vp, daddr_t blkno, void *tbuf, 288 size_t size, int bflags) 289 { 290 struct buf *bp; 291 int error; 292 293 bp = getiobuf(); 294 bp->b_vp = vp; 295 bp->b_blkno = blkno; 296 bp->b_bcount = bp->b_resid = size; 297 bp->b_flags = bflags; 298 bp->b_proc = curproc; 299 bp->b_data = tbuf; 300 301 VOP_STRATEGY(vp, bp); 302 error = biowait(bp); 303 304 putiobuf(bp); 305 return (error); 306 } 307