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