mfi_disk.c revision 158737
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: head/sys/dev/mfi/mfi_disk.c 158737 2006-05-18 23:30:48Z ambrisko $");
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/selinfo.h>
36#include <sys/module.h>
37#include <sys/malloc.h>
38#include <sys/uio.h>
39
40#include <sys/bio.h>
41#include <sys/bus.h>
42#include <sys/conf.h>
43#include <sys/disk.h>
44#include <geom/geom_disk.h>
45
46#include <vm/vm.h>
47#include <vm/pmap.h>
48
49#include <machine/md_var.h>
50#include <machine/bus.h>
51#include <sys/rman.h>
52
53#include <dev/mfi/mfireg.h>
54#include <dev/mfi/mfi_ioctl.h>
55#include <dev/mfi/mfivar.h>
56
57static int	mfi_disk_probe(device_t dev);
58static int	mfi_disk_attach(device_t dev);
59static int	mfi_disk_detach(device_t dev);
60
61static disk_open_t	mfi_disk_open;
62static disk_close_t	mfi_disk_close;
63static disk_strategy_t	mfi_disk_strategy;
64static dumper_t		mfi_disk_dump;
65
66static devclass_t	mfi_disk_devclass;
67
68struct mfi_disk {
69	device_t	ld_dev;
70	int		ld_id;
71	int		ld_unit;
72	struct mfi_softc *ld_controller;
73	struct mfi_ld	*ld_ld;
74	struct disk	*ld_disk;
75};
76
77static device_method_t mfi_disk_methods[] = {
78	DEVMETHOD(device_probe,		mfi_disk_probe),
79	DEVMETHOD(device_attach,	mfi_disk_attach),
80	DEVMETHOD(device_detach,	mfi_disk_detach),
81	{ 0, 0 }
82};
83
84static driver_t mfi_disk_driver = {
85	"mfid",
86	mfi_disk_methods,
87	sizeof(struct mfi_disk)
88};
89
90DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
91
92static int
93mfi_disk_probe(device_t dev)
94{
95
96	return (0);
97}
98
99static int
100mfi_disk_attach(device_t dev)
101{
102	struct mfi_disk *sc;
103	struct mfi_ld *ld;
104	uint64_t sectors;
105	uint32_t secsize;
106
107	sc = device_get_softc(dev);
108	ld = device_get_ivars(dev);
109
110	sc->ld_dev = dev;
111	sc->ld_id = ld->ld_id;
112	sc->ld_unit = device_get_unit(dev);
113	sc->ld_ld = device_get_ivars(dev);
114	sc->ld_controller = device_get_softc(device_get_parent(dev));
115
116	sectors = sc->ld_ld->ld_sectors;
117	secsize = sc->ld_ld->ld_secsize;
118	if (secsize != MFI_SECTOR_LEN) {
119		device_printf(sc->ld_dev, "Reported sector length %d is not "
120		    "512, aborting\n", secsize);
121		free(sc->ld_ld, M_MFIBUF);
122		return (EINVAL);
123	}
124	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, ld, ld_link);
125
126	device_printf(dev, "%juMB (%ju sectors) RAID\n",
127	    sectors / (1024 * 1024 / secsize), sectors);
128
129	sc->ld_disk = disk_alloc();
130	sc->ld_disk->d_drv1 = sc;
131	sc->ld_disk->d_maxsize = sc->ld_controller->mfi_max_io * secsize;
132	sc->ld_disk->d_name = "mfid";
133	sc->ld_disk->d_open = mfi_disk_open;
134	sc->ld_disk->d_close = mfi_disk_close;
135	sc->ld_disk->d_strategy = mfi_disk_strategy;
136	sc->ld_disk->d_dump = mfi_disk_dump;
137	sc->ld_disk->d_unit = sc->ld_unit;
138	sc->ld_disk->d_sectorsize = secsize;
139	sc->ld_disk->d_mediasize = sectors * secsize;
140	if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) {
141		sc->ld_disk->d_fwheads = 255;
142		sc->ld_disk->d_fwsectors = 63;
143	} else {
144		sc->ld_disk->d_fwheads = 64;
145		sc->ld_disk->d_fwsectors = 32;
146	}
147	disk_create(sc->ld_disk, DISK_VERSION);
148
149	return (0);
150}
151
152static int
153mfi_disk_detach(device_t dev)
154{
155	struct mfi_disk *sc;
156
157	sc = device_get_softc(dev);
158
159	if (sc->ld_disk->d_flags & DISKFLAG_OPEN)
160		return (EBUSY);
161
162	disk_destroy(sc->ld_disk);
163	return (0);
164}
165
166static int
167mfi_disk_open(struct disk *dp)
168{
169
170	return (0);
171}
172
173static int
174mfi_disk_close(struct disk *dp)
175{
176
177	return (0);
178}
179
180static void
181mfi_disk_strategy(struct bio *bio)
182{
183	struct mfi_disk *sc;
184	struct mfi_softc *controller;
185
186	sc = bio->bio_disk->d_drv1;
187
188	if (sc == NULL) {
189		bio->bio_error = EINVAL;
190		bio->bio_flags |= BIO_ERROR;
191		bio->bio_resid = bio->bio_bcount;
192		biodone(bio);
193		return;
194	}
195
196	controller = sc->ld_controller;
197	bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
198	mtx_lock(&controller->mfi_io_lock);
199	mfi_enqueue_bio(controller, bio);
200	mfi_startio(controller);
201	mtx_unlock(&controller->mfi_io_lock);
202	return;
203}
204
205void
206mfi_disk_complete(struct bio *bio)
207{
208	struct mfi_disk *sc;
209	struct mfi_frame_header *hdr;
210
211	sc = bio->bio_disk->d_drv1;
212	hdr = bio->bio_driver1;
213
214	if (bio->bio_flags & BIO_ERROR) {
215		if (bio->bio_error == 0)
216			bio->bio_error = EIO;
217		disk_err(bio, "hard error", -1, 1);
218	} else {
219		bio->bio_resid = 0;
220	}
221	biodone(bio);
222}
223
224static int
225mfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
226{
227	struct mfi_disk *sc;
228	struct mfi_softc *parent_sc;
229	struct disk *dp;
230	int error;
231
232	dp = arg;
233	sc = dp->d_drv1;
234	parent_sc = sc->ld_controller;
235
236	if (len > 0) {
237		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
238		    sc->ld_ld->ld_secsize, virt, len)) != 0)
239			return (error);
240	} else {
241		/* mfi_sync_cache(parent_sc, sc->ld_id); */
242	}
243
244	return (0);
245}
246