1 /* $OpenBSD: softraid_raid0.c,v 1.26 2012/01/22 11:13:32 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. */ 47 int sr_raid0_create(struct sr_discipline *, struct bioc_createraid *, 48 int, int64_t); 49 int sr_raid0_assemble(struct sr_discipline *, struct bioc_createraid *, 50 int); 51 int sr_raid0_alloc_resources(struct sr_discipline *); 52 int sr_raid0_free_resources(struct sr_discipline *); 53 int sr_raid0_rw(struct sr_workunit *); 54 void sr_raid0_intr(struct buf *); 55 56 /* Discipline initialisation. */ 57 void 58 sr_raid0_discipline_init(struct sr_discipline *sd) 59 { 60 61 /* Fill out discipline members. */ 62 sd->sd_type = SR_MD_RAID0; 63 sd->sd_capabilities = SR_CAP_SYSTEM_DISK | SR_CAP_AUTO_ASSEMBLE; 64 sd->sd_max_wu = SR_RAID0_NOWU; 65 66 /* Setup discipline specific function pointers. */ 67 sd->sd_alloc_resources = sr_raid0_alloc_resources; 68 sd->sd_assemble = sr_raid0_assemble; 69 sd->sd_create = sr_raid0_create; 70 sd->sd_free_resources = sr_raid0_free_resources; 71 sd->sd_scsi_rw = sr_raid0_rw; 72 } 73 74 int 75 sr_raid0_create(struct sr_discipline *sd, struct bioc_createraid *bc, 76 int no_chunk, int64_t coerced_size) 77 { 78 if (no_chunk < 2) { 79 sr_error(sd->sd_sc, "RAID 0 requires two or more chunks"); 80 return EINVAL; 81 } 82 83 /* 84 * XXX add variable strip size later even though MAXPHYS is really 85 * the clever value, users like to tinker with that type of stuff. 86 */ 87 strlcpy(sd->sd_name, "RAID 0", sizeof(sd->sd_name)); 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 sd->sd_max_ccb_per_wu = 93 (MAXPHYS / sd->sd_meta->ssdi.ssd_strip_size + 1) * 94 SR_RAID0_NOWU * no_chunk; 95 96 return 0; 97 } 98 99 int 100 sr_raid0_assemble(struct sr_discipline *sd, struct bioc_createraid *bc, 101 int no_chunks) 102 { 103 104 sd->sd_max_ccb_per_wu = 105 (MAXPHYS / sd->sd_meta->ssdi.ssd_strip_size + 1) * 106 SR_RAID0_NOWU * sd->sd_meta->ssdi.ssd_chunk_no; 107 108 return 0; 109 } 110 111 int 112 sr_raid0_alloc_resources(struct sr_discipline *sd) 113 { 114 int rv = EINVAL; 115 116 if (!sd) 117 return (rv); 118 119 DNPRINTF(SR_D_DIS, "%s: sr_raid0_alloc_resources\n", 120 DEVNAME(sd->sd_sc)); 121 122 if (sr_wu_alloc(sd)) 123 goto bad; 124 if (sr_ccb_alloc(sd)) 125 goto bad; 126 127 /* setup runtime values */ 128 sd->mds.mdd_raid0.sr0_strip_bits = 129 sr_validate_stripsize(sd->sd_meta->ssdi.ssd_strip_size); 130 if (sd->mds.mdd_raid0.sr0_strip_bits == -1) 131 goto bad; 132 133 rv = 0; 134 bad: 135 return (rv); 136 } 137 138 int 139 sr_raid0_free_resources(struct sr_discipline *sd) 140 { 141 int rv = EINVAL; 142 143 if (!sd) 144 return (rv); 145 146 DNPRINTF(SR_D_DIS, "%s: sr_raid0_free_resources\n", 147 DEVNAME(sd->sd_sc)); 148 149 sr_wu_free(sd); 150 sr_ccb_free(sd); 151 152 rv = 0; 153 return (rv); 154 } 155 156 int 157 sr_raid0_rw(struct sr_workunit *wu) 158 { 159 struct sr_discipline *sd = wu->swu_dis; 160 struct scsi_xfer *xs = wu->swu_xs; 161 struct sr_ccb *ccb; 162 struct sr_chunk *scp; 163 int s; 164 daddr64_t blk, lbaoffs, strip_no, chunk, stripoffs; 165 daddr64_t strip_size, no_chunk, chunkoffs, physoffs; 166 daddr64_t strip_bits, length, leftover; 167 u_int8_t *data; 168 169 /* blk and scsi error will be handled by sr_validate_io */ 170 if (sr_validate_io(wu, &blk, "sr_raid0_rw")) 171 goto bad; 172 173 strip_size = sd->sd_meta->ssdi.ssd_strip_size; 174 strip_bits = sd->mds.mdd_raid0.sr0_strip_bits; 175 no_chunk = sd->sd_meta->ssdi.ssd_chunk_no; 176 177 DNPRINTF(SR_D_DIS, "%s: %s: front end io: lba %lld size %d\n", 178 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, 179 blk, xs->datalen); 180 181 /* all offs are in bytes */ 182 lbaoffs = blk << DEV_BSHIFT; 183 strip_no = lbaoffs >> strip_bits; 184 chunk = strip_no % no_chunk; 185 stripoffs = lbaoffs & (strip_size - 1); 186 chunkoffs = (strip_no / no_chunk) << strip_bits; 187 physoffs = chunkoffs + stripoffs + 188 (sd->sd_meta->ssd_data_offset << DEV_BSHIFT); 189 length = MIN(xs->datalen, strip_size - stripoffs); 190 leftover = xs->datalen; 191 data = xs->data; 192 for (wu->swu_io_count = 1;; wu->swu_io_count++) { 193 /* make sure chunk is online */ 194 scp = sd->sd_vol.sv_chunks[chunk]; 195 if (scp->src_meta.scm_status != BIOC_SDONLINE) { 196 goto bad; 197 } 198 199 ccb = sr_ccb_get(sd); 200 if (!ccb) { 201 /* should never happen but handle more gracefully */ 202 printf("%s: %s: too many ccbs queued\n", 203 DEVNAME(sd->sd_sc), 204 sd->sd_meta->ssd_devname); 205 goto bad; 206 } 207 208 DNPRINTF(SR_D_DIS, "%s: %s raid io: lbaoffs: %lld " 209 "strip_no: %lld chunk: %lld stripoffs: %lld " 210 "chunkoffs: %lld physoffs: %lld length: %lld " 211 "leftover: %lld data: %p\n", 212 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, lbaoffs, 213 strip_no, chunk, stripoffs, chunkoffs, physoffs, length, 214 leftover, data); 215 216 ccb->ccb_buf.b_flags = B_CALL | B_PHYS; 217 ccb->ccb_buf.b_iodone = sr_raid0_intr; 218 ccb->ccb_buf.b_blkno = physoffs >> DEV_BSHIFT; 219 ccb->ccb_buf.b_bcount = length; 220 ccb->ccb_buf.b_bufsize = length; 221 ccb->ccb_buf.b_resid = length; 222 ccb->ccb_buf.b_data = data; 223 ccb->ccb_buf.b_error = 0; 224 ccb->ccb_buf.b_proc = curproc; 225 ccb->ccb_buf.b_bq = NULL; 226 ccb->ccb_wu = wu; 227 ccb->ccb_buf.b_flags |= xs->flags & SCSI_DATA_IN ? 228 B_READ : B_WRITE; 229 ccb->ccb_target = chunk; 230 ccb->ccb_buf.b_dev = sd->sd_vol.sv_chunks[chunk]->src_dev_mm; 231 ccb->ccb_buf.b_vp = sd->sd_vol.sv_chunks[chunk]->src_vn; 232 if ((ccb->ccb_buf.b_flags & B_READ) == 0) 233 ccb->ccb_buf.b_vp->v_numoutput++; 234 LIST_INIT(&ccb->ccb_buf.b_dep); 235 TAILQ_INSERT_TAIL(&wu->swu_ccb, ccb, ccb_link); 236 237 DNPRINTF(SR_D_DIS, "%s: %s: sr_raid0: b_bcount: %d " 238 "b_blkno: %lld b_flags 0x%0x b_data %p\n", 239 DEVNAME(sd->sd_sc), sd->sd_meta->ssd_devname, 240 ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_blkno, 241 ccb->ccb_buf.b_flags, ccb->ccb_buf.b_data); 242 243 leftover -= length; 244 if (leftover == 0) 245 break; 246 247 data += length; 248 if (++chunk > no_chunk - 1) { 249 chunk = 0; 250 physoffs += length; 251 } else if (wu->swu_io_count == 1) 252 physoffs -= stripoffs; 253 length = MIN(leftover,strip_size); 254 } 255 256 s = splbio(); 257 258 if (sr_check_io_collision(wu)) 259 goto queued; 260 261 sr_raid_startwu(wu); 262 queued: 263 splx(s); 264 return (0); 265 bad: 266 /* wu is unwound by sr_wu_put */ 267 return (1); 268 } 269 270 void 271 sr_raid0_intr(struct buf *bp) 272 { 273 struct sr_ccb *ccb = (struct sr_ccb *)bp; 274 struct sr_workunit *wu = ccb->ccb_wu, *wup; 275 struct sr_discipline *sd = wu->swu_dis; 276 struct scsi_xfer *xs = wu->swu_xs; 277 struct sr_softc *sc = sd->sd_sc; 278 int s, pend; 279 280 DNPRINTF(SR_D_INTR, "%s: sr_intr bp %x xs %x\n", 281 DEVNAME(sc), bp, xs); 282 283 DNPRINTF(SR_D_INTR, "%s: sr_intr: b_bcount: %d b_resid: %d" 284 " b_flags: 0x%0x block: %lld target: %d\n", DEVNAME(sc), 285 ccb->ccb_buf.b_bcount, ccb->ccb_buf.b_resid, ccb->ccb_buf.b_flags, 286 ccb->ccb_buf.b_blkno, ccb->ccb_target); 287 288 s = splbio(); 289 290 if (ccb->ccb_buf.b_flags & B_ERROR) { 291 printf("%s: i/o error on block %lld target: %d b_error: %d\n", 292 DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target, 293 ccb->ccb_buf.b_error); 294 DNPRINTF(SR_D_INTR, "%s: i/o error on block %lld target: %d\n", 295 DEVNAME(sc), ccb->ccb_buf.b_blkno, ccb->ccb_target); 296 wu->swu_ios_failed++; 297 ccb->ccb_state = SR_CCB_FAILED; 298 if (ccb->ccb_target != -1) 299 sd->sd_set_chunk_state(sd, ccb->ccb_target, 300 BIOC_SDOFFLINE); 301 else 302 panic("%s: invalid target on wu: %p", DEVNAME(sc), wu); 303 } else { 304 ccb->ccb_state = SR_CCB_OK; 305 wu->swu_ios_succeeded++; 306 } 307 wu->swu_ios_complete++; 308 309 DNPRINTF(SR_D_INTR, "%s: sr_intr: comp: %d count: %d failed: %d\n", 310 DEVNAME(sc), wu->swu_ios_complete, wu->swu_io_count, 311 wu->swu_ios_failed); 312 313 if (wu->swu_ios_complete >= wu->swu_io_count) { 314 if (wu->swu_ios_failed) 315 goto bad; 316 317 xs->error = XS_NOERROR; 318 xs->resid = 0; 319 320 pend = 0; 321 TAILQ_FOREACH(wup, &sd->sd_wu_pendq, swu_link) { 322 if (wu == wup) { 323 /* wu on pendq, remove */ 324 TAILQ_REMOVE(&sd->sd_wu_pendq, wu, swu_link); 325 pend = 1; 326 327 if (wu->swu_collider) { 328 /* restart deferred wu */ 329 wu->swu_collider->swu_state = 330 SR_WU_INPROGRESS; 331 TAILQ_REMOVE(&sd->sd_wu_defq, 332 wu->swu_collider, swu_link); 333 sr_raid_startwu(wu->swu_collider); 334 } 335 break; 336 } 337 } 338 339 if (!pend) 340 printf("%s: wu: %p not on pending queue\n", 341 DEVNAME(sc), wu); 342 343 sr_scsi_done(sd, xs); 344 345 if (sd->sd_sync && sd->sd_wu_pending == 0) 346 wakeup(sd); 347 } 348 349 splx(s); 350 return; 351 bad: 352 xs->error = XS_DRIVER_STUFFUP; 353 sr_scsi_done(sd, xs); 354 splx(s); 355 } 356