1 /* $OpenBSD: softraid_raid0.c,v 1.47 2014/11/18 02:37:30 tedu 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/malloc.h> 26 #include <sys/kernel.h> 27 #include <sys/disk.h> 28 #include <sys/rwlock.h> 29 #include <sys/queue.h> 30 #include <sys/fcntl.h> 31 #include <sys/disklabel.h> 32 #include <sys/mount.h> 33 #include <sys/sensors.h> 34 #include <sys/stat.h> 35 #include <sys/conf.h> 36 #include <sys/uio.h> 37 38 #include <scsi/scsi_all.h> 39 #include <scsi/scsiconf.h> 40 #include <scsi/scsi_disk.h> 41 42 #include <dev/softraidvar.h> 43 44 /* RAID 0 functions. */ 45 int sr_raid0_create(struct sr_discipline *, struct bioc_createraid *, 46 int, int64_t); 47 int sr_raid0_assemble(struct sr_discipline *, struct bioc_createraid *, 48 int, void *); 49 int sr_raid0_init(struct sr_discipline *); 50 int sr_raid0_rw(struct sr_workunit *); 51 52 /* Discipline initialisation. */ 53 void 54 sr_raid0_discipline_init(struct sr_discipline *sd) 55 { 56 57 /* Fill out discipline members. */ 58 sd->sd_type = SR_MD_RAID0; 59 strlcpy(sd->sd_name, "RAID 0", sizeof(sd->sd_name)); 60 sd->sd_capabilities = SR_CAP_SYSTEM_DISK | SR_CAP_AUTO_ASSEMBLE; 61 sd->sd_max_wu = SR_RAID0_NOWU; 62 63 /* Setup discipline specific function pointers. */ 64 sd->sd_assemble = sr_raid0_assemble; 65 sd->sd_create = sr_raid0_create; 66 sd->sd_scsi_rw = sr_raid0_rw; 67 } 68 69 int 70 sr_raid0_create(struct sr_discipline *sd, struct bioc_createraid *bc, 71 int no_chunk, int64_t coerced_size) 72 { 73 if (no_chunk < 2) { 74 sr_error(sd->sd_sc, "%s requires two or more chunks", 75 sd->sd_name); 76 return EINVAL; 77 } 78 79 /* 80 * XXX add variable strip size later even though MAXPHYS is really 81 * the clever value, users like to tinker with that type of stuff. 82 */ 83 sd->sd_meta->ssdi.ssd_strip_size = MAXPHYS; 84 sd->sd_meta->ssdi.ssd_size = (coerced_size & 85 ~(((u_int64_t)sd->sd_meta->ssdi.ssd_strip_size >> 86 DEV_BSHIFT) - 1)) * no_chunk; 87 88 return sr_raid0_init(sd); 89 } 90 91 int 92 sr_raid0_assemble(struct sr_discipline *sd, struct bioc_createraid *bc, 93 int no_chunks, void *data) 94 { 95 return sr_raid0_init(sd); 96 } 97 98 int 99 sr_raid0_init(struct sr_discipline *sd) 100 { 101 /* Initialise runtime values. */ 102 sd->mds.mdd_raid0.sr0_strip_bits = 103 sr_validate_stripsize(sd->sd_meta->ssdi.ssd_strip_size); 104 if (sd->mds.mdd_raid0.sr0_strip_bits == -1) { 105 sr_error(sd->sd_sc, "invalid strip size", sd->sd_name); 106 return EINVAL; 107 } 108 sd->sd_max_ccb_per_wu = 109 (MAXPHYS / sd->sd_meta->ssdi.ssd_strip_size + 1) * 110 SR_RAID0_NOWU * sd->sd_meta->ssdi.ssd_chunk_no; 111 112 return 0; 113 } 114 115 int 116 sr_raid0_rw(struct sr_workunit *wu) 117 { 118 struct sr_discipline *sd = wu->swu_dis; 119 struct scsi_xfer *xs = wu->swu_xs; 120 struct sr_ccb *ccb; 121 struct sr_chunk *scp; 122 daddr_t blk; 123 int64_t chunkoffs, lbaoffs, physoffs, stripoffs; 124 int64_t strip_bits, strip_no, strip_size; 125 int64_t chunk, no_chunk; 126 int64_t length, leftover; 127 u_int8_t *data; 128 129 /* blk and scsi error will be handled by sr_validate_io */ 130 if (sr_validate_io(wu, &blk, "sr_raid0_rw")) 131 goto bad; 132 133 strip_size = sd->sd_meta->ssdi.ssd_strip_size; 134 strip_bits = sd->mds.mdd_raid0.sr0_strip_bits; 135 no_chunk = sd->sd_meta->ssdi.ssd_chunk_no; 136 137 DNPRINTF(SR_D_DIS, "%s: %s: front end io: lba %lld size %d\n", 138 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, 139 (long long)blk, xs->datalen); 140 141 /* all offs are in bytes */ 142 lbaoffs = blk << DEV_BSHIFT; 143 strip_no = lbaoffs >> strip_bits; 144 chunk = strip_no % no_chunk; 145 stripoffs = lbaoffs & (strip_size - 1); 146 chunkoffs = (strip_no / no_chunk) << strip_bits; 147 physoffs = chunkoffs + stripoffs + 148 (sd->sd_meta->ssd_data_offset << DEV_BSHIFT); 149 length = MIN(xs->datalen, strip_size - stripoffs); 150 leftover = xs->datalen; 151 data = xs->data; 152 for (;;) { 153 /* make sure chunk is online */ 154 scp = sd->sd_vol.sv_chunks[chunk]; 155 if (scp->src_meta.scm_status != BIOC_SDONLINE) 156 goto bad; 157 158 DNPRINTF(SR_D_DIS, "%s: %s %s io lbaoffs %lld " 159 "strip_no %lld chunk %lld stripoffs %lld " 160 "chunkoffs %lld physoffs %lld length %lld " 161 "leftover %lld data %p\n", 162 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, sd->sd_name, 163 lbaoffs, strip_no, chunk, stripoffs, chunkoffs, physoffs, 164 length, leftover, data); 165 166 blk = physoffs >> DEV_BSHIFT; 167 ccb = sr_ccb_rw(sd, chunk, blk, length, data, xs->flags, 0); 168 if (!ccb) { 169 /* should never happen but handle more gracefully */ 170 printf("%s: %s: too many ccbs queued\n", 171 DEVNAME(sd->sd_sc), 172 sd->sd_meta->ssd_devname); 173 goto bad; 174 } 175 sr_wu_enqueue_ccb(wu, ccb); 176 177 leftover -= length; 178 if (leftover == 0) 179 break; 180 181 data += length; 182 if (++chunk > no_chunk - 1) { 183 chunk = 0; 184 physoffs += length; 185 } else if (wu->swu_io_count == 1) 186 physoffs -= stripoffs; 187 length = MIN(leftover,strip_size); 188 } 189 190 sr_schedule_wu(wu); 191 192 return (0); 193 194 bad: 195 /* wu is unwound by sr_wu_put */ 196 return (1); 197 } 198