softraid_raid0.c revision 1.37
1/* $OpenBSD: softraid_raid0.c,v 1.37 2013/03/31 10:41:16 jsing Exp $ */ 2/* 3 * Copyright (c) 2008 Marco Peereboom <marco@peereboom.us> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include "bio.h" 19 20#include <sys/param.h> 21#include <sys/systm.h> 22#include <sys/buf.h> 23#include <sys/device.h> 24#include <sys/ioctl.h> 25#include <sys/proc.h> 26#include <sys/malloc.h> 27#include <sys/kernel.h> 28#include <sys/disk.h> 29#include <sys/rwlock.h> 30#include <sys/queue.h> 31#include <sys/fcntl.h> 32#include <sys/disklabel.h> 33#include <sys/mount.h> 34#include <sys/sensors.h> 35#include <sys/stat.h> 36#include <sys/conf.h> 37#include <sys/uio.h> 38 39#include <scsi/scsi_all.h> 40#include <scsi/scsiconf.h> 41#include <scsi/scsi_disk.h> 42 43#include <dev/softraidvar.h> 44#include <dev/rndvar.h> 45 46/* RAID 0 functions. */ 47int sr_raid0_create(struct sr_discipline *, struct bioc_createraid *, 48 int, int64_t); 49int sr_raid0_assemble(struct sr_discipline *, struct bioc_createraid *, 50 int, void *); 51int sr_raid0_init(struct sr_discipline *); 52int sr_raid0_alloc_resources(struct sr_discipline *); 53int sr_raid0_free_resources(struct sr_discipline *); 54int sr_raid0_rw(struct sr_workunit *); 55 56/* Discipline initialisation. */ 57void 58sr_raid0_discipline_init(struct sr_discipline *sd) 59{ 60 61 /* Fill out discipline members. */ 62 sd->sd_type = SR_MD_RAID0; 63 strlcpy(sd->sd_name, "RAID 0", sizeof(sd->sd_name)); 64 sd->sd_capabilities = SR_CAP_SYSTEM_DISK | SR_CAP_AUTO_ASSEMBLE; 65 sd->sd_max_wu = SR_RAID0_NOWU; 66 67 /* Setup discipline specific function pointers. */ 68 sd->sd_alloc_resources = sr_raid0_alloc_resources; 69 sd->sd_assemble = sr_raid0_assemble; 70 sd->sd_create = sr_raid0_create; 71 sd->sd_free_resources = sr_raid0_free_resources; 72 sd->sd_scsi_rw = sr_raid0_rw; 73} 74 75int 76sr_raid0_create(struct sr_discipline *sd, struct bioc_createraid *bc, 77 int no_chunk, int64_t coerced_size) 78{ 79 if (no_chunk < 2) { 80 sr_error(sd->sd_sc, "RAID 0 requires two or more chunks"); 81 return EINVAL; 82 } 83 84 /* 85 * XXX add variable strip size later even though MAXPHYS is really 86 * the clever value, users like to tinker with that type of stuff. 87 */ 88 sd->sd_meta->ssdi.ssd_strip_size = MAXPHYS; 89 sd->sd_meta->ssdi.ssd_size = (coerced_size & 90 ~((sd->sd_meta->ssdi.ssd_strip_size >> DEV_BSHIFT) - 1)) * no_chunk; 91 92 return sr_raid0_init(sd); 93} 94 95int 96sr_raid0_assemble(struct sr_discipline *sd, struct bioc_createraid *bc, 97 int no_chunks, void *data) 98{ 99 return sr_raid0_init(sd); 100} 101 102int 103sr_raid0_init(struct sr_discipline *sd) 104{ 105 /* Initialise runtime values. */ 106 sd->mds.mdd_raid0.sr0_strip_bits = 107 sr_validate_stripsize(sd->sd_meta->ssdi.ssd_strip_size); 108 if (sd->mds.mdd_raid0.sr0_strip_bits == -1) { 109 sr_error(sd->sd_sc, "invalid strip size", sd->sd_name); 110 return EINVAL; 111 } 112 sd->sd_max_ccb_per_wu = 113 (MAXPHYS / sd->sd_meta->ssdi.ssd_strip_size + 1) * 114 SR_RAID0_NOWU * sd->sd_meta->ssdi.ssd_chunk_no; 115 116 return 0; 117} 118 119int 120sr_raid0_alloc_resources(struct sr_discipline *sd) 121{ 122 int rv = EINVAL; 123 124 DNPRINTF(SR_D_DIS, "%s: sr_raid0_alloc_resources\n", 125 DEVNAME(sd->sd_sc)); 126 127 if (sr_wu_alloc(sd)) 128 goto bad; 129 if (sr_ccb_alloc(sd)) 130 goto bad; 131 132 rv = 0; 133bad: 134 return (rv); 135} 136 137int 138sr_raid0_free_resources(struct sr_discipline *sd) 139{ 140 int rv = EINVAL; 141 142 DNPRINTF(SR_D_DIS, "%s: sr_raid0_free_resources\n", 143 DEVNAME(sd->sd_sc)); 144 145 sr_wu_free(sd); 146 sr_ccb_free(sd); 147 148 rv = 0; 149 return (rv); 150} 151 152int 153sr_raid0_rw(struct sr_workunit *wu) 154{ 155 struct sr_discipline *sd = wu->swu_dis; 156 struct scsi_xfer *xs = wu->swu_xs; 157 struct sr_ccb *ccb; 158 struct sr_chunk *scp; 159 int s; 160 daddr64_t blk, lbaoffs, strip_no, chunk, stripoffs; 161 daddr64_t strip_size, no_chunk, chunkoffs, physoffs; 162 daddr64_t strip_bits, length, leftover; 163 u_int8_t *data; 164 165 /* blk and scsi error will be handled by sr_validate_io */ 166 if (sr_validate_io(wu, &blk, "sr_raid0_rw")) 167 goto bad; 168 169 strip_size = sd->sd_meta->ssdi.ssd_strip_size; 170 strip_bits = sd->mds.mdd_raid0.sr0_strip_bits; 171 no_chunk = sd->sd_meta->ssdi.ssd_chunk_no; 172 173 DNPRINTF(SR_D_DIS, "%s: %s: front end io: lba %lld size %d\n", 174 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, 175 blk, xs->datalen); 176 177 /* all offs are in bytes */ 178 lbaoffs = blk << DEV_BSHIFT; 179 strip_no = lbaoffs >> strip_bits; 180 chunk = strip_no % no_chunk; 181 stripoffs = lbaoffs & (strip_size - 1); 182 chunkoffs = (strip_no / no_chunk) << strip_bits; 183 physoffs = chunkoffs + stripoffs + 184 (sd->sd_meta->ssd_data_offset << DEV_BSHIFT); 185 length = MIN(xs->datalen, strip_size - stripoffs); 186 leftover = xs->datalen; 187 data = xs->data; 188 for (;;) { 189 /* make sure chunk is online */ 190 scp = sd->sd_vol.sv_chunks[chunk]; 191 if (scp->src_meta.scm_status != BIOC_SDONLINE) 192 goto bad; 193 194 DNPRINTF(SR_D_DIS, "%s: %s %s io lbaoffs %lld " 195 "strip_no %lld chunk %lld stripoffs %lld " 196 "chunkoffs %lld physoffs %lld length %lld " 197 "leftover %lld data %p\n", 198 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, sd->sd_name, 199 lbaoffs, strip_no, chunk, stripoffs, chunkoffs, physoffs, 200 length, leftover, data); 201 202 blk = physoffs >> DEV_BSHIFT; 203 ccb = sr_ccb_rw(sd, chunk, blk, length, data, xs->flags, 0); 204 if (!ccb) { 205 /* should never happen but handle more gracefully */ 206 printf("%s: %s: too many ccbs queued\n", 207 DEVNAME(sd->sd_sc), 208 sd->sd_meta->ssd_devname); 209 goto bad; 210 } 211 sr_wu_enqueue_ccb(wu, ccb); 212 213 leftover -= length; 214 if (leftover == 0) 215 break; 216 217 data += length; 218 if (++chunk > no_chunk - 1) { 219 chunk = 0; 220 physoffs += length; 221 } else if (wu->swu_io_count == 1) 222 physoffs -= stripoffs; 223 length = MIN(leftover,strip_size); 224 } 225 226 s = splbio(); 227 228 if (sr_check_io_collision(wu)) 229 goto queued; 230 231 sr_raid_startwu(wu); 232queued: 233 splx(s); 234 return (0); 235bad: 236 /* wu is unwound by sr_wu_put */ 237 return (1); 238} 239