xref: /freebsd/sys/dev/mfi/mfi_disk.c (revision 7dfd9569a2f0637fb9a48157b1c1bfe5709faee3)
1 /*-
2  * Copyright (c) 2006 IronPort Systems
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "opt_mfi.h"
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/malloc.h>
37 
38 #include <sys/bio.h>
39 #include <sys/bus.h>
40 #include <sys/conf.h>
41 #include <sys/disk.h>
42 #include <geom/geom_disk.h>
43 
44 #include <vm/vm.h>
45 #include <vm/pmap.h>
46 
47 #include <machine/md_var.h>
48 #include <machine/bus.h>
49 #include <sys/rman.h>
50 
51 #include <dev/mfi/mfireg.h>
52 #include <dev/mfi/mfi_ioctl.h>
53 #include <dev/mfi/mfivar.h>
54 
55 static int	mfi_disk_probe(device_t dev);
56 static int	mfi_disk_attach(device_t dev);
57 static int	mfi_disk_detach(device_t dev);
58 
59 static disk_open_t	mfi_disk_open;
60 static disk_close_t	mfi_disk_close;
61 static disk_strategy_t	mfi_disk_strategy;
62 static dumper_t		mfi_disk_dump;
63 
64 static devclass_t	mfi_disk_devclass;
65 
66 struct mfi_disk {
67 	device_t	ld_dev;
68 	int		ld_id;
69 	int		ld_unit;
70 	struct mfi_softc *ld_controller;
71 	struct mfi_ld	*ld_ld;
72 	struct disk	*ld_disk;
73 };
74 
75 static device_method_t mfi_disk_methods[] = {
76 	DEVMETHOD(device_probe,		mfi_disk_probe),
77 	DEVMETHOD(device_attach,	mfi_disk_attach),
78 	DEVMETHOD(device_detach,	mfi_disk_detach),
79 	{ 0, 0 }
80 };
81 
82 static driver_t mfi_disk_driver = {
83 	"mfid",
84 	mfi_disk_methods,
85 	sizeof(struct mfi_disk)
86 };
87 
88 DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
89 
90 static int
91 mfi_disk_probe(device_t dev)
92 {
93 
94 	return (0);
95 }
96 
97 static int
98 mfi_disk_attach(device_t dev)
99 {
100 	struct mfi_disk *sc;
101 	struct mfi_ld *ld;
102 	uint64_t sectors;
103 	uint32_t secsize;
104 
105 	sc = device_get_softc(dev);
106 	ld = device_get_ivars(dev);
107 
108 	sc->ld_dev = dev;
109 	sc->ld_id = ld->ld_id;
110 	sc->ld_unit = device_get_unit(dev);
111 	sc->ld_ld = device_get_ivars(dev);
112 	sc->ld_controller = device_get_softc(device_get_parent(dev));
113 
114 	sectors = sc->ld_ld->ld_sectors;
115 	secsize = sc->ld_ld->ld_secsize;
116 	if (secsize != MFI_SECTOR_LEN) {
117 		device_printf(sc->ld_dev, "Reported sector length %d is not "
118 		    "512, aborting\n", secsize);
119 		free(sc->ld_ld, M_MFIBUF);
120 		return (EINVAL);
121 	}
122 	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, ld, ld_link);
123 
124 	device_printf(dev, "%juMB (%ju sectors) RAID\n",
125 	    sectors / (1024 * 1024 / secsize), sectors);
126 
127 	sc->ld_disk = disk_alloc();
128 	sc->ld_disk->d_drv1 = sc;
129 	sc->ld_disk->d_maxsize = sc->ld_controller->mfi_max_io * secsize;
130 	sc->ld_disk->d_name = "mfid";
131 	sc->ld_disk->d_open = mfi_disk_open;
132 	sc->ld_disk->d_close = mfi_disk_close;
133 	sc->ld_disk->d_strategy = mfi_disk_strategy;
134 	sc->ld_disk->d_dump = mfi_disk_dump;
135 	sc->ld_disk->d_unit = sc->ld_unit;
136 	sc->ld_disk->d_sectorsize = secsize;
137 	sc->ld_disk->d_mediasize = sectors * secsize;
138 	if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) {
139 		sc->ld_disk->d_fwheads = 255;
140 		sc->ld_disk->d_fwsectors = 63;
141 	} else {
142 		sc->ld_disk->d_fwheads = 64;
143 		sc->ld_disk->d_fwsectors = 32;
144 	}
145 	disk_create(sc->ld_disk, DISK_VERSION);
146 
147 	return (0);
148 }
149 
150 static int
151 mfi_disk_detach(device_t dev)
152 {
153 	struct mfi_disk *sc;
154 
155 	sc = device_get_softc(dev);
156 
157 	if (sc->ld_disk->d_flags & DISKFLAG_OPEN)
158 		return (EBUSY);
159 
160 	disk_destroy(sc->ld_disk);
161 	return (0);
162 }
163 
164 static int
165 mfi_disk_open(struct disk *dp)
166 {
167 
168 	return (0);
169 }
170 
171 static int
172 mfi_disk_close(struct disk *dp)
173 {
174 
175 	return (0);
176 }
177 
178 static void
179 mfi_disk_strategy(struct bio *bio)
180 {
181 	struct mfi_disk *sc;
182 	struct mfi_softc *controller;
183 
184 	sc = bio->bio_disk->d_drv1;
185 
186 	if (sc == NULL) {
187 		bio->bio_error = EINVAL;
188 		bio->bio_flags |= BIO_ERROR;
189 		bio->bio_resid = bio->bio_bcount;
190 		biodone(bio);
191 		return;
192 	}
193 
194 	controller = sc->ld_controller;
195 	bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
196 	mtx_lock(&controller->mfi_io_lock);
197 	mfi_enqueue_bio(controller, bio);
198 	mfi_startio(controller);
199 	mtx_unlock(&controller->mfi_io_lock);
200 	return;
201 }
202 
203 void
204 mfi_disk_complete(struct bio *bio)
205 {
206 	struct mfi_disk *sc;
207 	struct mfi_frame_header *hdr;
208 
209 	sc = bio->bio_disk->d_drv1;
210 	hdr = bio->bio_driver1;
211 
212 	if (bio->bio_flags & BIO_ERROR) {
213 		if (bio->bio_error == 0)
214 			bio->bio_error = EIO;
215 		disk_err(bio, "hard error", -1, 1);
216 	} else {
217 		bio->bio_resid = 0;
218 	}
219 	biodone(bio);
220 }
221 
222 static int
223 mfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
224 {
225 	struct mfi_disk *sc;
226 	struct mfi_softc *parent_sc;
227 	struct disk *dp;
228 	int error;
229 
230 	dp = arg;
231 	sc = dp->d_drv1;
232 	parent_sc = sc->ld_controller;
233 
234 	if (len > 0) {
235 		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
236 		    sc->ld_ld->ld_secsize, virt, len)) != 0)
237 			return (error);
238 	} else {
239 		/* mfi_sync_cache(parent_sc, sc->ld_id); */
240 	}
241 
242 	return (0);
243 }
244