xref: /dflybsd-src/sys/dev/raid/mfi/mfi_disk.c (revision 249d29c853eea97a029baf4136cd1688d7a4cd68)
1*249d29c8SSascha Wildner /*-
2*249d29c8SSascha Wildner  * Copyright (c) 2006 IronPort Systems
3*249d29c8SSascha Wildner  * All rights reserved.
4*249d29c8SSascha Wildner  *
5*249d29c8SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6*249d29c8SSascha Wildner  * modification, are permitted provided that the following conditions
7*249d29c8SSascha Wildner  * are met:
8*249d29c8SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9*249d29c8SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10*249d29c8SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11*249d29c8SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12*249d29c8SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13*249d29c8SSascha Wildner  *
14*249d29c8SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*249d29c8SSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*249d29c8SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*249d29c8SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*249d29c8SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*249d29c8SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*249d29c8SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*249d29c8SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*249d29c8SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*249d29c8SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*249d29c8SSascha Wildner  * SUCH DAMAGE.
25*249d29c8SSascha Wildner  *
26*249d29c8SSascha Wildner  * $FreeBSD: src/sys/dev/mfi/mfi_disk.c,v 1.8 2008/11/17 23:30:19 jhb Exp $
27*249d29c8SSascha Wildner  */
28*249d29c8SSascha Wildner 
29*249d29c8SSascha Wildner #include "opt_mfi.h"
30*249d29c8SSascha Wildner 
31*249d29c8SSascha Wildner #include <sys/param.h>
32*249d29c8SSascha Wildner #include <sys/systm.h>
33*249d29c8SSascha Wildner #include <sys/kernel.h>
34*249d29c8SSascha Wildner #include <sys/module.h>
35*249d29c8SSascha Wildner #include <sys/malloc.h>
36*249d29c8SSascha Wildner #include <sys/uio.h>
37*249d29c8SSascha Wildner 
38*249d29c8SSascha Wildner #include <sys/buf2.h>
39*249d29c8SSascha Wildner #include <sys/bus.h>
40*249d29c8SSascha Wildner #include <sys/conf.h>
41*249d29c8SSascha Wildner #include <sys/disk.h>
42*249d29c8SSascha Wildner 
43*249d29c8SSascha Wildner #include <vm/vm.h>
44*249d29c8SSascha Wildner #include <vm/pmap.h>
45*249d29c8SSascha Wildner 
46*249d29c8SSascha Wildner #include <machine/md_var.h>
47*249d29c8SSascha Wildner #include <sys/rman.h>
48*249d29c8SSascha Wildner 
49*249d29c8SSascha Wildner #include <dev/raid/mfi/mfireg.h>
50*249d29c8SSascha Wildner #include <dev/raid/mfi/mfi_ioctl.h>
51*249d29c8SSascha Wildner #include <dev/raid/mfi/mfivar.h>
52*249d29c8SSascha Wildner 
53*249d29c8SSascha Wildner static int	mfi_disk_probe(device_t dev);
54*249d29c8SSascha Wildner static int	mfi_disk_attach(device_t dev);
55*249d29c8SSascha Wildner static int	mfi_disk_detach(device_t dev);
56*249d29c8SSascha Wildner 
57*249d29c8SSascha Wildner static d_open_t		mfi_disk_open;
58*249d29c8SSascha Wildner static d_close_t	mfi_disk_close;
59*249d29c8SSascha Wildner static d_strategy_t	mfi_disk_strategy;
60*249d29c8SSascha Wildner static d_dump_t		mfi_disk_dump;
61*249d29c8SSascha Wildner 
62*249d29c8SSascha Wildner static struct dev_ops mfi_disk_ops = {
63*249d29c8SSascha Wildner 	{ "mfid", 0, D_DISK },
64*249d29c8SSascha Wildner 	.d_open = mfi_disk_open,
65*249d29c8SSascha Wildner 	.d_close = mfi_disk_close,
66*249d29c8SSascha Wildner 	.d_strategy = mfi_disk_strategy,
67*249d29c8SSascha Wildner 	.d_dump = mfi_disk_dump,
68*249d29c8SSascha Wildner };
69*249d29c8SSascha Wildner 
70*249d29c8SSascha Wildner static devclass_t	mfi_disk_devclass;
71*249d29c8SSascha Wildner 
72*249d29c8SSascha Wildner static device_method_t mfi_disk_methods[] = {
73*249d29c8SSascha Wildner 	DEVMETHOD(device_probe,		mfi_disk_probe),
74*249d29c8SSascha Wildner 	DEVMETHOD(device_attach,	mfi_disk_attach),
75*249d29c8SSascha Wildner 	DEVMETHOD(device_detach,	mfi_disk_detach),
76*249d29c8SSascha Wildner 	{ 0, 0 }
77*249d29c8SSascha Wildner };
78*249d29c8SSascha Wildner 
79*249d29c8SSascha Wildner static driver_t mfi_disk_driver = {
80*249d29c8SSascha Wildner 	"mfid",
81*249d29c8SSascha Wildner 	mfi_disk_methods,
82*249d29c8SSascha Wildner 	sizeof(struct mfi_disk)
83*249d29c8SSascha Wildner };
84*249d29c8SSascha Wildner 
85*249d29c8SSascha Wildner DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
86*249d29c8SSascha Wildner 
87*249d29c8SSascha Wildner static int
88*249d29c8SSascha Wildner mfi_disk_probe(device_t dev)
89*249d29c8SSascha Wildner {
90*249d29c8SSascha Wildner 
91*249d29c8SSascha Wildner 	return (0);
92*249d29c8SSascha Wildner }
93*249d29c8SSascha Wildner 
94*249d29c8SSascha Wildner static int
95*249d29c8SSascha Wildner mfi_disk_attach(device_t dev)
96*249d29c8SSascha Wildner {
97*249d29c8SSascha Wildner 	struct mfi_disk *sc;
98*249d29c8SSascha Wildner 	struct mfi_ld_info *ld_info;
99*249d29c8SSascha Wildner 	struct disk_info info;
100*249d29c8SSascha Wildner 	uint64_t sectors;
101*249d29c8SSascha Wildner 	uint32_t secsize;
102*249d29c8SSascha Wildner 	char *state;
103*249d29c8SSascha Wildner 
104*249d29c8SSascha Wildner 	sc = device_get_softc(dev);
105*249d29c8SSascha Wildner 	ld_info = device_get_ivars(dev);
106*249d29c8SSascha Wildner 
107*249d29c8SSascha Wildner 	sc->ld_dev = dev;
108*249d29c8SSascha Wildner 	sc->ld_id = ld_info->ld_config.properties.ld.v.target_id;
109*249d29c8SSascha Wildner 	sc->ld_unit = device_get_unit(dev);
110*249d29c8SSascha Wildner 	sc->ld_info = ld_info;
111*249d29c8SSascha Wildner 	sc->ld_controller = device_get_softc(device_get_parent(dev));
112*249d29c8SSascha Wildner 	sc->ld_flags = 0;
113*249d29c8SSascha Wildner 
114*249d29c8SSascha Wildner 	sectors = ld_info->size;
115*249d29c8SSascha Wildner 	secsize = MFI_SECTOR_LEN;
116*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
117*249d29c8SSascha Wildner 	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
118*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
119*249d29c8SSascha Wildner 
120*249d29c8SSascha Wildner 	switch (ld_info->ld_config.params.state) {
121*249d29c8SSascha Wildner 	case MFI_LD_STATE_OFFLINE:
122*249d29c8SSascha Wildner 		state = "offline";
123*249d29c8SSascha Wildner 		break;
124*249d29c8SSascha Wildner 	case MFI_LD_STATE_PARTIALLY_DEGRADED:
125*249d29c8SSascha Wildner 		state = "partially degraded";
126*249d29c8SSascha Wildner 		break;
127*249d29c8SSascha Wildner 	case MFI_LD_STATE_DEGRADED:
128*249d29c8SSascha Wildner 		state = "degraded";
129*249d29c8SSascha Wildner 		break;
130*249d29c8SSascha Wildner 	case MFI_LD_STATE_OPTIMAL:
131*249d29c8SSascha Wildner 		state = "optimal";
132*249d29c8SSascha Wildner 		break;
133*249d29c8SSascha Wildner 	default:
134*249d29c8SSascha Wildner 		state = "unknown";
135*249d29c8SSascha Wildner 		break;
136*249d29c8SSascha Wildner 	}
137*249d29c8SSascha Wildner 	device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n",
138*249d29c8SSascha Wildner 		      sectors / (1024 * 1024 / secsize), sectors,
139*249d29c8SSascha Wildner 		      ld_info->ld_config.properties.name,
140*249d29c8SSascha Wildner 		      state);
141*249d29c8SSascha Wildner 
142*249d29c8SSascha Wildner 	sc->ld_disk.d_cdev = disk_create(sc->ld_unit, &sc->ld_disk,
143*249d29c8SSascha Wildner 	    &mfi_disk_ops);
144*249d29c8SSascha Wildner 	sc->ld_disk.d_cdev->si_drv1 = sc;
145*249d29c8SSascha Wildner 	sc->ld_disk.d_cdev->si_iosize_max =
146*249d29c8SSascha Wildner 	    min(sc->ld_controller->mfi_max_io * secsize,
147*249d29c8SSascha Wildner 		(sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE);
148*249d29c8SSascha Wildner 
149*249d29c8SSascha Wildner 	bzero(&info, sizeof(info));
150*249d29c8SSascha Wildner 	info.d_media_blksize = secsize;	/* mandatory */
151*249d29c8SSascha Wildner 	info.d_media_blocks = sectors;
152*249d29c8SSascha Wildner 
153*249d29c8SSascha Wildner 	if (info.d_media_blocks >= (1 * 1024 * 1024)) {
154*249d29c8SSascha Wildner 		info.d_nheads = 255;
155*249d29c8SSascha Wildner 		info.d_secpertrack = 63;
156*249d29c8SSascha Wildner 	} else {
157*249d29c8SSascha Wildner 		info.d_nheads = 64;
158*249d29c8SSascha Wildner 		info.d_secpertrack = 32;
159*249d29c8SSascha Wildner 	}
160*249d29c8SSascha Wildner 
161*249d29c8SSascha Wildner 	disk_setdiskinfo(&sc->ld_disk, &info);
162*249d29c8SSascha Wildner 
163*249d29c8SSascha Wildner 	return (0);
164*249d29c8SSascha Wildner }
165*249d29c8SSascha Wildner 
166*249d29c8SSascha Wildner static int
167*249d29c8SSascha Wildner mfi_disk_detach(device_t dev)
168*249d29c8SSascha Wildner {
169*249d29c8SSascha Wildner 	struct mfi_disk *sc;
170*249d29c8SSascha Wildner 
171*249d29c8SSascha Wildner 	sc = device_get_softc(dev);
172*249d29c8SSascha Wildner 
173*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
174*249d29c8SSascha Wildner 	if (((sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
175*249d29c8SSascha Wildner 	    (sc->ld_controller->mfi_keep_deleted_volumes ||
176*249d29c8SSascha Wildner 	    sc->ld_controller->mfi_detaching)) {
177*249d29c8SSascha Wildner 		lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
178*249d29c8SSascha Wildner 		return (EBUSY);
179*249d29c8SSascha Wildner 	}
180*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
181*249d29c8SSascha Wildner 
182*249d29c8SSascha Wildner 	disk_destroy(&sc->ld_disk);
183*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
184*249d29c8SSascha Wildner 	TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
185*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
186*249d29c8SSascha Wildner 	kfree(sc->ld_info, M_MFIBUF);
187*249d29c8SSascha Wildner 	return (0);
188*249d29c8SSascha Wildner }
189*249d29c8SSascha Wildner 
190*249d29c8SSascha Wildner static int
191*249d29c8SSascha Wildner mfi_disk_open(struct dev_open_args *ap)
192*249d29c8SSascha Wildner {
193*249d29c8SSascha Wildner 	struct mfi_disk *sc = ap->a_head.a_dev->si_drv1;
194*249d29c8SSascha Wildner 	int error;
195*249d29c8SSascha Wildner 
196*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
197*249d29c8SSascha Wildner 	if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED)
198*249d29c8SSascha Wildner 		error = ENXIO;
199*249d29c8SSascha Wildner 	else {
200*249d29c8SSascha Wildner 		sc->ld_flags |= MFI_DISK_FLAGS_OPEN;
201*249d29c8SSascha Wildner 		error = 0;
202*249d29c8SSascha Wildner 	}
203*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
204*249d29c8SSascha Wildner 
205*249d29c8SSascha Wildner 	return (error);
206*249d29c8SSascha Wildner }
207*249d29c8SSascha Wildner 
208*249d29c8SSascha Wildner static int
209*249d29c8SSascha Wildner mfi_disk_close(struct dev_close_args *ap)
210*249d29c8SSascha Wildner {
211*249d29c8SSascha Wildner 	struct mfi_disk *sc = ap->a_head.a_dev->si_drv1;
212*249d29c8SSascha Wildner 
213*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_EXCLUSIVE);
214*249d29c8SSascha Wildner 	sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN;
215*249d29c8SSascha Wildner 	lockmgr(&sc->ld_controller->mfi_io_lock, LK_RELEASE);
216*249d29c8SSascha Wildner 
217*249d29c8SSascha Wildner 	return (0);
218*249d29c8SSascha Wildner }
219*249d29c8SSascha Wildner 
220*249d29c8SSascha Wildner int
221*249d29c8SSascha Wildner mfi_disk_disable(struct mfi_disk *sc)
222*249d29c8SSascha Wildner {
223*249d29c8SSascha Wildner 
224*249d29c8SSascha Wildner 	KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0);
225*249d29c8SSascha Wildner 	if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
226*249d29c8SSascha Wildner 		if (sc->ld_controller->mfi_delete_busy_volumes)
227*249d29c8SSascha Wildner 			return (0);
228*249d29c8SSascha Wildner 		device_printf(sc->ld_dev, "Unable to delete busy device\n");
229*249d29c8SSascha Wildner 		return (EBUSY);
230*249d29c8SSascha Wildner 	}
231*249d29c8SSascha Wildner 	sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
232*249d29c8SSascha Wildner 	return (0);
233*249d29c8SSascha Wildner }
234*249d29c8SSascha Wildner 
235*249d29c8SSascha Wildner void
236*249d29c8SSascha Wildner mfi_disk_enable(struct mfi_disk *sc)
237*249d29c8SSascha Wildner {
238*249d29c8SSascha Wildner 
239*249d29c8SSascha Wildner 	KKASSERT(lockstatus(&sc->ld_controller->mfi_io_lock, curthread) != 0);
240*249d29c8SSascha Wildner 	sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED;
241*249d29c8SSascha Wildner }
242*249d29c8SSascha Wildner 
243*249d29c8SSascha Wildner static int
244*249d29c8SSascha Wildner mfi_disk_strategy(struct dev_strategy_args *ap)
245*249d29c8SSascha Wildner {
246*249d29c8SSascha Wildner 	struct bio *bio = ap->a_bio;
247*249d29c8SSascha Wildner 	struct buf *bp = bio->bio_buf;
248*249d29c8SSascha Wildner 	struct mfi_disk *sc = ap->a_head.a_dev->si_drv1;
249*249d29c8SSascha Wildner 	struct mfi_softc *controller;
250*249d29c8SSascha Wildner 
251*249d29c8SSascha Wildner 	if (sc == NULL) {
252*249d29c8SSascha Wildner 		bp->b_error = EINVAL;
253*249d29c8SSascha Wildner 		bp->b_flags |= B_ERROR;
254*249d29c8SSascha Wildner 		bp->b_resid = bp->b_bcount;
255*249d29c8SSascha Wildner 		biodone(bio);
256*249d29c8SSascha Wildner 		return (0);
257*249d29c8SSascha Wildner 	}
258*249d29c8SSascha Wildner 
259*249d29c8SSascha Wildner 	/*
260*249d29c8SSascha Wildner 	 * XXX swildner
261*249d29c8SSascha Wildner 	 *
262*249d29c8SSascha Wildner 	 * If it's a null transfer, do nothing. FreeBSD's original driver
263*249d29c8SSascha Wildner 	 * doesn't have this, but that caused hard error messages (even
264*249d29c8SSascha Wildner 	 * though everything else continued to work fine). Interestingly,
265*249d29c8SSascha Wildner 	 * only when HAMMER was used.
266*249d29c8SSascha Wildner 	 *
267*249d29c8SSascha Wildner 	 * Several others of our RAID drivers have this check, such as
268*249d29c8SSascha Wildner 	 * aac(4) and ida(4), so we insert it here, too.
269*249d29c8SSascha Wildner 	 *
270*249d29c8SSascha Wildner 	 * The cause of null transfers is yet unknown.
271*249d29c8SSascha Wildner 	 */
272*249d29c8SSascha Wildner 	if (bp->b_bcount == 0) {
273*249d29c8SSascha Wildner 		bp->b_resid = bp->b_bcount;
274*249d29c8SSascha Wildner 		biodone(bio);
275*249d29c8SSascha Wildner 		return (0);
276*249d29c8SSascha Wildner 	}
277*249d29c8SSascha Wildner 
278*249d29c8SSascha Wildner 	controller = sc->ld_controller;
279*249d29c8SSascha Wildner 	bio->bio_driver_info = sc;
280*249d29c8SSascha Wildner 	lockmgr(&controller->mfi_io_lock, LK_EXCLUSIVE);
281*249d29c8SSascha Wildner 	mfi_enqueue_bio(controller, bio);
282*249d29c8SSascha Wildner 	mfi_startio(controller);
283*249d29c8SSascha Wildner 	lockmgr(&controller->mfi_io_lock, LK_RELEASE);
284*249d29c8SSascha Wildner 	return (0);
285*249d29c8SSascha Wildner }
286*249d29c8SSascha Wildner 
287*249d29c8SSascha Wildner void
288*249d29c8SSascha Wildner mfi_disk_complete(struct bio *bio)
289*249d29c8SSascha Wildner {
290*249d29c8SSascha Wildner 	struct mfi_disk *sc = bio->bio_driver_info;
291*249d29c8SSascha Wildner 	struct buf *bp = bio->bio_buf;
292*249d29c8SSascha Wildner 
293*249d29c8SSascha Wildner 	if (bp->b_flags & B_ERROR) {
294*249d29c8SSascha Wildner 		if (bp->b_error == 0)
295*249d29c8SSascha Wildner 			bp->b_error = EIO;
296*249d29c8SSascha Wildner 		diskerr(bio, sc->ld_disk.d_cdev, "hard error", -1, 1);
297*249d29c8SSascha Wildner 		kprintf("\n");
298*249d29c8SSascha Wildner 	} else {
299*249d29c8SSascha Wildner 		bp->b_resid = 0;
300*249d29c8SSascha Wildner 	}
301*249d29c8SSascha Wildner 	biodone(bio);
302*249d29c8SSascha Wildner }
303*249d29c8SSascha Wildner 
304*249d29c8SSascha Wildner static int
305*249d29c8SSascha Wildner mfi_disk_dump(struct dev_dump_args *ap)
306*249d29c8SSascha Wildner {
307*249d29c8SSascha Wildner 	cdev_t dev = ap->a_head.a_dev;
308*249d29c8SSascha Wildner 	off_t offset = ap->a_offset;
309*249d29c8SSascha Wildner 	void *virt = ap->a_virtual;
310*249d29c8SSascha Wildner 	size_t len = ap->a_length;
311*249d29c8SSascha Wildner 	struct mfi_disk *sc;
312*249d29c8SSascha Wildner 	struct mfi_softc *parent_sc;
313*249d29c8SSascha Wildner 	int error;
314*249d29c8SSascha Wildner 
315*249d29c8SSascha Wildner 	sc = dev->si_drv1;
316*249d29c8SSascha Wildner 	parent_sc = sc->ld_controller;
317*249d29c8SSascha Wildner 
318*249d29c8SSascha Wildner 	if (len > 0) {
319*249d29c8SSascha Wildner 		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
320*249d29c8SSascha Wildner 		    MFI_SECTOR_LEN, virt, len)) != 0)
321*249d29c8SSascha Wildner 			return (error);
322*249d29c8SSascha Wildner 	} else {
323*249d29c8SSascha Wildner 		/* mfi_sync_cache(parent_sc, sc->ld_id); */
324*249d29c8SSascha Wildner 	}
325*249d29c8SSascha Wildner 
326*249d29c8SSascha Wildner 	return (0);
327*249d29c8SSascha Wildner }
328