xref: /openbsd/sys/dev/softraid_raid1c.c (revision 87edded1)
1 /* $OpenBSD: softraid_raid1c.c,v 1.6 2021/10/24 14:50:42 tobhe Exp $ */
2 /*
3  * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
4  * Copyright (c) 2008 Hans-Joerg Hoexer <hshoexer@openbsd.org>
5  * Copyright (c) 2008 Damien Miller <djm@mindrot.org>
6  * Copyright (c) 2009 Joel Sing <jsing@openbsd.org>
7  * Copyright (c) 2020 Stefan Sperling <stsp@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include "bio.h"
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/buf.h>
27 #include <sys/device.h>
28 #include <sys/ioctl.h>
29 #include <sys/malloc.h>
30 #include <sys/kernel.h>
31 #include <sys/disk.h>
32 #include <sys/rwlock.h>
33 #include <sys/queue.h>
34 #include <sys/fcntl.h>
35 #include <sys/mount.h>
36 #include <sys/sensors.h>
37 #include <sys/stat.h>
38 #include <sys/task.h>
39 #include <sys/conf.h>
40 #include <sys/uio.h>
41 
42 #include <crypto/cryptodev.h>
43 
44 #include <scsi/scsi_all.h>
45 #include <scsi/scsiconf.h>
46 #include <scsi/scsi_disk.h>
47 
48 #include <dev/softraidvar.h>
49 
50 /* RAID 1C functions. */
51 int	sr_raid1c_create(struct sr_discipline *, struct bioc_createraid *,
52 	    int, int64_t);
53 int	sr_raid1c_add_offline_chunks(struct sr_discipline *, int);
54 int	sr_raid1c_assemble(struct sr_discipline *, struct bioc_createraid *,
55 	    int, void *);
56 int	sr_raid1c_alloc_resources(struct sr_discipline *);
57 void	sr_raid1c_free_resources(struct sr_discipline *sd);
58 int	sr_raid1c_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd);
59 int	sr_raid1c_meta_opt_handler(struct sr_discipline *,
60 	    struct sr_meta_opt_hdr *);
61 int	sr_raid1c_rw(struct sr_workunit *);
62 int	sr_raid1c_dev_rw(struct sr_workunit *, struct sr_crypto_wu *);
63 void	sr_raid1c_done(struct sr_workunit *wu);
64 
65 /* RAID1 functions */
66 extern int	sr_raid1_init(struct sr_discipline *sd);
67 extern int	sr_raid1_assemble(struct sr_discipline *,
68 		    struct bioc_createraid *, int, void *);
69 extern int	sr_raid1_wu_done(struct sr_workunit *);
70 extern void	sr_raid1_set_chunk_state(struct sr_discipline *, int, int);
71 extern void	sr_raid1_set_vol_state(struct sr_discipline *);
72 
73 /* CRYPTO raid functions */
74 extern struct sr_crypto_wu *sr_crypto_prepare(struct sr_workunit *,
75 		    struct sr_crypto *, int);
76 extern int	sr_crypto_meta_create(struct sr_discipline *,
77 		    struct sr_crypto *, struct bioc_createraid *);
78 extern int	sr_crypto_set_key(struct sr_discipline *,
79 		    struct sr_crypto *, struct bioc_createraid *, int, void *);
80 extern int	sr_crypto_alloc_resources_internal(struct sr_discipline *,
81 		    struct sr_crypto *);
82 extern void	sr_crypto_free_resources_internal(struct sr_discipline *,
83 		    struct sr_crypto *);
84 extern int	sr_crypto_ioctl_internal(struct sr_discipline *,
85 		    struct sr_crypto *, struct bioc_discipline *);
86 int		sr_crypto_meta_opt_handler_internal(struct sr_discipline *,
87 		    struct sr_crypto *, struct sr_meta_opt_hdr *);
88 void		sr_crypto_done_internal(struct sr_workunit *,
89 		    struct sr_crypto *);
90 
91 /* Discipline initialisation. */
92 void
sr_raid1c_discipline_init(struct sr_discipline * sd)93 sr_raid1c_discipline_init(struct sr_discipline *sd)
94 {
95 	int i;
96 
97 	/* Fill out discipline members. */
98 	sd->sd_wu_size = sizeof(struct sr_crypto_wu);
99 	sd->sd_type = SR_MD_RAID1C;
100 	strlcpy(sd->sd_name, "RAID 1C", sizeof(sd->sd_name));
101 	sd->sd_capabilities = SR_CAP_SYSTEM_DISK | SR_CAP_AUTO_ASSEMBLE |
102 	    SR_CAP_REBUILD | SR_CAP_REDUNDANT;
103 	sd->sd_max_wu = SR_RAID1C_NOWU;
104 
105 	for (i = 0; i < SR_CRYPTO_MAXKEYS; i++)
106 		sd->mds.mdd_raid1c.sr1c_crypto.scr_sid[i] = (u_int64_t)-1;
107 
108 	/* Setup discipline specific function pointers. */
109 	sd->sd_alloc_resources = sr_raid1c_alloc_resources;
110 	sd->sd_assemble = sr_raid1c_assemble;
111 	sd->sd_create = sr_raid1c_create;
112 	sd->sd_free_resources = sr_raid1c_free_resources;
113 	sd->sd_ioctl_handler = sr_raid1c_ioctl;
114 	sd->sd_meta_opt_handler = sr_raid1c_meta_opt_handler;
115 	sd->sd_scsi_rw = sr_raid1c_rw;
116 	sd->sd_scsi_done = sr_raid1c_done;
117 	sd->sd_scsi_wu_done = sr_raid1_wu_done;
118 	sd->sd_set_chunk_state = sr_raid1_set_chunk_state;
119 	sd->sd_set_vol_state = sr_raid1_set_vol_state;
120 }
121 
122 int
sr_raid1c_create(struct sr_discipline * sd,struct bioc_createraid * bc,int no_chunk,int64_t coerced_size)123 sr_raid1c_create(struct sr_discipline *sd, struct bioc_createraid *bc,
124     int no_chunk, int64_t coerced_size)
125 {
126 	int rv;
127 
128 	if (no_chunk < 2) {
129 		sr_error(sd->sd_sc, "%s requires two or more chunks",
130 		    sd->sd_name);
131 		return EINVAL;
132 	}
133 
134 	sd->sd_meta->ssdi.ssd_size = coerced_size;
135 
136 	rv = sr_raid1_init(sd);
137 	if (rv)
138 		return rv;
139 
140 	return sr_crypto_meta_create(sd, &sd->mds.mdd_raid1c.sr1c_crypto, bc);
141 }
142 
143 int
sr_raid1c_add_offline_chunks(struct sr_discipline * sd,int no_chunk)144 sr_raid1c_add_offline_chunks(struct sr_discipline *sd, int no_chunk)
145 {
146 	struct sr_chunk	*ch_entry, *ch_prev;
147 	struct sr_chunk **chunks;
148 	int c;
149 
150 	chunks = mallocarray(sd->sd_meta->ssdi.ssd_chunk_no,
151 	    sizeof(struct sr_chunk *), M_DEVBUF, M_WAITOK | M_ZERO);
152 
153 	for (c = 0; c < no_chunk; c++)
154 		chunks[c] = sd->sd_vol.sv_chunks[c];
155 
156 	for (c = no_chunk; c < sd->sd_meta->ssdi.ssd_chunk_no; c++) {
157 		ch_prev = chunks[c - 1];
158 		ch_entry = malloc(sizeof(struct sr_chunk), M_DEVBUF,
159 		    M_WAITOK | M_ZERO);
160 		ch_entry->src_meta.scm_status = BIOC_SDOFFLINE;
161 		ch_entry->src_dev_mm = NODEV;
162 		SLIST_INSERT_AFTER(ch_prev, ch_entry, src_link);
163 		chunks[c] = ch_entry;
164 	}
165 
166 	free(sd->sd_vol.sv_chunks, M_DEVBUF,
167 	    sizeof(struct sr_chunk *) * no_chunk);
168 	sd->sd_vol.sv_chunks = chunks;
169 
170 	return (0);
171 }
172 
173 int
sr_raid1c_assemble(struct sr_discipline * sd,struct bioc_createraid * bc,int no_chunk,void * data)174 sr_raid1c_assemble(struct sr_discipline *sd, struct bioc_createraid *bc,
175     int no_chunk, void *data)
176 {
177 	struct sr_raid1c *mdd_raid1c = &sd->mds.mdd_raid1c;
178 	int rv;
179 
180 	/* Create NODEV place-holders for missing chunks. */
181 	if (no_chunk < sd->sd_meta->ssdi.ssd_chunk_no) {
182 		rv = sr_raid1c_add_offline_chunks(sd, no_chunk);
183 		if (rv)
184 			return (rv);
185 	}
186 
187 	rv = sr_raid1_assemble(sd, bc, no_chunk, NULL);
188 	if (rv)
189 		return (rv);
190 
191 	return sr_crypto_set_key(sd, &mdd_raid1c->sr1c_crypto, bc,
192 	    no_chunk, data);
193 }
194 
195 int
sr_raid1c_ioctl(struct sr_discipline * sd,struct bioc_discipline * bd)196 sr_raid1c_ioctl(struct sr_discipline *sd, struct bioc_discipline *bd)
197 {
198 	struct sr_raid1c *mdd_raid1c = &sd->mds.mdd_raid1c;
199 	return sr_crypto_ioctl_internal(sd, &mdd_raid1c->sr1c_crypto, bd);
200 }
201 
202 int
sr_raid1c_alloc_resources(struct sr_discipline * sd)203 sr_raid1c_alloc_resources(struct sr_discipline *sd)
204 {
205 	struct sr_raid1c *mdd_raid1c = &sd->mds.mdd_raid1c;
206 	return sr_crypto_alloc_resources_internal(sd, &mdd_raid1c->sr1c_crypto);
207 }
208 
209 void
sr_raid1c_free_resources(struct sr_discipline * sd)210 sr_raid1c_free_resources(struct sr_discipline *sd)
211 {
212 	struct sr_raid1c *mdd_raid1c = &sd->mds.mdd_raid1c;
213 	sr_crypto_free_resources_internal(sd, &mdd_raid1c->sr1c_crypto);
214 }
215 
216 int
sr_raid1c_dev_rw(struct sr_workunit * wu,struct sr_crypto_wu * crwu)217 sr_raid1c_dev_rw(struct sr_workunit *wu, struct sr_crypto_wu *crwu)
218 {
219 	struct sr_discipline	*sd = wu->swu_dis;
220 	struct scsi_xfer	*xs = wu->swu_xs;
221 	struct sr_raid1c	*mdd_raid1c = &sd->mds.mdd_raid1c;
222 	struct sr_ccb		*ccb;
223 	struct uio		*uio;
224 	struct sr_chunk		*scp;
225 	int			ios, chunk, i, rt;
226 	daddr_t			blkno;
227 
228 	blkno = wu->swu_blk_start;
229 
230 	if (xs->flags & SCSI_DATA_IN)
231 		ios = 1;
232 	else
233 		ios = sd->sd_meta->ssdi.ssd_chunk_no;
234 
235 	for (i = 0; i < ios; i++) {
236 		if (xs->flags & SCSI_DATA_IN) {
237 			rt = 0;
238 ragain:
239 			/* interleave reads */
240 			chunk = mdd_raid1c->sr1c_raid1.sr1_counter++ %
241 			    sd->sd_meta->ssdi.ssd_chunk_no;
242 			scp = sd->sd_vol.sv_chunks[chunk];
243 			switch (scp->src_meta.scm_status) {
244 			case BIOC_SDONLINE:
245 			case BIOC_SDSCRUB:
246 				break;
247 
248 			case BIOC_SDOFFLINE:
249 			case BIOC_SDREBUILD:
250 			case BIOC_SDHOTSPARE:
251 				if (rt++ < sd->sd_meta->ssdi.ssd_chunk_no)
252 					goto ragain;
253 
254 				/* FALLTHROUGH */
255 			default:
256 				/* volume offline */
257 				printf("%s: is offline, cannot read\n",
258 				    DEVNAME(sd->sd_sc));
259 				goto bad;
260 			}
261 		} else {
262 			/* writes go on all working disks */
263 			chunk = i;
264 			scp = sd->sd_vol.sv_chunks[chunk];
265 			switch (scp->src_meta.scm_status) {
266 			case BIOC_SDONLINE:
267 				if (ISSET(wu->swu_flags, SR_WUF_REBUILD))
268 					continue;
269 				break;
270 
271 			case BIOC_SDSCRUB:
272 			case BIOC_SDREBUILD:
273 				break;
274 
275 			case BIOC_SDHOTSPARE: /* should never happen */
276 			case BIOC_SDOFFLINE:
277 				continue;
278 
279 			default:
280 				goto bad;
281 			}
282 		}
283 
284 		ccb = sr_ccb_rw(sd, chunk, blkno, xs->datalen, xs->data,
285 		    xs->flags, 0);
286 		if (!ccb) {
287 			/* should never happen but handle more gracefully */
288 			printf("%s: %s: too many ccbs queued\n",
289 			    DEVNAME(sd->sd_sc),
290 			    sd->sd_meta->ssd_devname);
291 			goto bad;
292 		}
293 		if (!ISSET(xs->flags, SCSI_DATA_IN) &&
294 		    !ISSET(wu->swu_flags, SR_WUF_REBUILD)) {
295 			uio = crwu->cr_crp->crp_buf;
296 			ccb->ccb_buf.b_data = uio->uio_iov->iov_base;
297 			ccb->ccb_opaque = crwu;
298 		}
299 		sr_wu_enqueue_ccb(wu, ccb);
300 	}
301 
302 	sr_schedule_wu(wu);
303 
304 	return (0);
305 
306 bad:
307 	return (EINVAL);
308 }
309 
310 int
sr_raid1c_meta_opt_handler(struct sr_discipline * sd,struct sr_meta_opt_hdr * om)311 sr_raid1c_meta_opt_handler(struct sr_discipline *sd, struct sr_meta_opt_hdr *om)
312 {
313 	struct sr_raid1c *mdd_raid1c = &sd->mds.mdd_raid1c;
314 	return sr_crypto_meta_opt_handler_internal(sd,
315 	    &mdd_raid1c->sr1c_crypto, om);
316 }
317 
318 int
sr_raid1c_rw(struct sr_workunit * wu)319 sr_raid1c_rw(struct sr_workunit *wu)
320 {
321 	struct sr_crypto_wu	*crwu;
322 	struct sr_raid1c	*mdd_raid1c;
323 	daddr_t			blkno;
324 	int			rv, err;
325 	int			s;
326 
327 	DNPRINTF(SR_D_DIS, "%s: sr_raid1c_rw wu %p\n",
328 	    DEVNAME(wu->swu_dis->sd_sc), wu);
329 
330 	if (sr_validate_io(wu, &blkno, "sr_raid1c_rw"))
331 		return (1);
332 
333 	if (ISSET(wu->swu_xs->flags, SCSI_DATA_OUT) &&
334 	    !ISSET(wu->swu_flags, SR_WUF_REBUILD)) {
335 		mdd_raid1c = &wu->swu_dis->mds.mdd_raid1c;
336 		crwu = sr_crypto_prepare(wu, &mdd_raid1c->sr1c_crypto, 1);
337 		rv = crypto_invoke(crwu->cr_crp);
338 
339 		DNPRINTF(SR_D_INTR, "%s: sr_raid1c_rw: wu %p xs: %p\n",
340 		    DEVNAME(wu->swu_dis->sd_sc), wu, wu->swu_xs);
341 
342 		if (rv) {
343 			/* fail io */
344 			wu->swu_xs->error = XS_DRIVER_STUFFUP;
345 			s = splbio();
346 			sr_scsi_done(wu->swu_dis, wu->swu_xs);
347 			splx(s);
348 		}
349 
350 		if ((err = sr_raid1c_dev_rw(wu, crwu)) != 0)
351 			return (err);
352 	} else
353 		rv = sr_raid1c_dev_rw(wu, NULL);
354 
355 	return (rv);
356 }
357 
358 void
sr_raid1c_done(struct sr_workunit * wu)359 sr_raid1c_done(struct sr_workunit *wu)
360 {
361 	struct sr_raid1c *mdd_raid1c = &wu->swu_dis->mds.mdd_raid1c;
362 	sr_crypto_done_internal(wu, &mdd_raid1c->sr1c_crypto);
363 }
364