mfi_disk.c revision 157114
197403Sobrien/*-
297403Sobrien * Copyright (c) 2006 IronPort Systems
397403Sobrien * All rights reserved.
4132720Skan *
597403Sobrien * Redistribution and use in source and binary forms, with or without
6132720Skan * modification, are permitted provided that the following conditions
797403Sobrien * are met:
897403Sobrien * 1. Redistributions of source code must retain the above copyright
997403Sobrien *    notice, this list of conditions and the following disclaimer.
1097403Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11132720Skan *    notice, this list of conditions and the following disclaimer in the
1297403Sobrien *    documentation and/or other materials provided with the distribution.
1397403Sobrien *
1497403Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1597403Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1697403Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132720Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18169691Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169691Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2097403Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2197403Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2297403Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2397403Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2497403Sobrien * SUCH DAMAGE.
2597403Sobrien */
2697403Sobrien
2797403Sobrien#include <sys/cdefs.h>
2897403Sobrien__FBSDID("$FreeBSD: head/sys/dev/mfi/mfi_disk.c 157114 2006-03-25 06:14:32Z scottl $");
2997403Sobrien
3097403Sobrien#include "opt_mfi.h"
31169691Skan
3297403Sobrien#include <sys/param.h>
3397403Sobrien#include <sys/systm.h>
34169691Skan#include <sys/kernel.h>
35132720Skan#include <sys/module.h>
3697403Sobrien#include <sys/malloc.h>
3797403Sobrien
3897403Sobrien#include <sys/bio.h>
3997403Sobrien#include <sys/bus.h>
4097403Sobrien#include <sys/conf.h>
4197403Sobrien#include <sys/disk.h>
4297403Sobrien#include <geom/geom_disk.h>
4397403Sobrien
44102782Skan#include <vm/vm.h>
45102782Skan#include <vm/pmap.h>
4697403Sobrien
47169691Skan#include <machine/md_var.h>
48169691Skan#include <machine/bus.h>
49169691Skan#include <sys/rman.h>
5097403Sobrien
5197403Sobrien#include <dev/mfi/mfireg.h>
52169691Skan#include <dev/mfi/mfi_ioctl.h>
5397403Sobrien#include <dev/mfi/mfivar.h>
5497403Sobrien
5597403Sobrienstatic int	mfi_disk_probe(device_t dev);
5697403Sobrienstatic int	mfi_disk_attach(device_t dev);
57static int	mfi_disk_detach(device_t dev);
58
59static disk_open_t	mfi_disk_open;
60static disk_close_t	mfi_disk_close;
61static disk_strategy_t	mfi_disk_strategy;
62static dumper_t		mfi_disk_dump;
63
64static devclass_t	mfi_disk_devclass;
65
66struct 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
75static 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
82static driver_t mfi_disk_driver = {
83	"mfid",
84	mfi_disk_methods,
85	sizeof(struct mfi_disk)
86};
87
88DRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
89
90static int
91mfi_disk_probe(device_t dev)
92{
93
94	return (0);
95}
96
97static int
98mfi_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
123	device_printf(dev, "%juMB (%ju sectors) RAID\n",
124	    sectors / (1024 * 1024 / secsize), sectors);
125
126	sc->ld_disk = disk_alloc();
127	sc->ld_disk->d_drv1 = sc;
128	sc->ld_disk->d_maxsize = sc->ld_controller->mfi_max_io * secsize;
129	sc->ld_disk->d_name = "mfid";
130	sc->ld_disk->d_open = mfi_disk_open;
131	sc->ld_disk->d_close = mfi_disk_close;
132	sc->ld_disk->d_strategy = mfi_disk_strategy;
133	sc->ld_disk->d_dump = mfi_disk_dump;
134	sc->ld_disk->d_unit = sc->ld_unit;
135	sc->ld_disk->d_sectorsize = secsize;
136	sc->ld_disk->d_mediasize = sectors * secsize;
137	if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) {
138		sc->ld_disk->d_fwheads = 255;
139		sc->ld_disk->d_fwsectors = 63;
140	} else {
141		sc->ld_disk->d_fwheads = 64;
142		sc->ld_disk->d_fwsectors = 32;
143	}
144	disk_create(sc->ld_disk, DISK_VERSION);
145
146	return (0);
147}
148
149static int
150mfi_disk_detach(device_t dev)
151{
152	struct mfi_disk *sc;
153
154	sc = device_get_softc(dev);
155
156	if (sc->ld_disk->d_flags & DISKFLAG_OPEN)
157		return (EBUSY);
158
159	disk_destroy(sc->ld_disk);
160	return (0);
161}
162
163static int
164mfi_disk_open(struct disk *dp)
165{
166
167	return (0);
168}
169
170static int
171mfi_disk_close(struct disk *dp)
172{
173
174	return (0);
175}
176
177static void
178mfi_disk_strategy(struct bio *bio)
179{
180	struct mfi_disk *sc;
181	struct mfi_softc *controller;
182
183	sc = bio->bio_disk->d_drv1;
184
185	if (sc == NULL) {
186		bio->bio_error = EINVAL;
187		bio->bio_flags |= BIO_ERROR;
188		bio->bio_resid = bio->bio_bcount;
189		biodone(bio);
190		return;
191	}
192
193	controller = sc->ld_controller;
194	bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
195	mtx_lock(&controller->mfi_io_lock);
196	mfi_enqueue_bio(controller, bio);
197	mfi_startio(controller);
198	mtx_unlock(&controller->mfi_io_lock);
199	return;
200}
201
202void
203mfi_disk_complete(struct bio *bio)
204{
205	struct mfi_disk *sc;
206	struct mfi_frame_header *hdr;
207
208	sc = bio->bio_disk->d_drv1;
209	hdr = bio->bio_driver1;
210
211	if (bio->bio_flags & BIO_ERROR) {
212		if (bio->bio_error == 0)
213			bio->bio_error = EIO;
214		disk_err(bio, "hard error", -1, 1);
215	} else {
216		bio->bio_resid = 0;
217	}
218	biodone(bio);
219}
220
221static int
222mfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
223{
224	struct mfi_disk *sc;
225	struct mfi_softc *parent_sc;
226	struct disk *dp;
227	int error;
228
229	dp = arg;
230	sc = dp->d_drv1;
231	parent_sc = sc->ld_controller;
232
233	if (len > 0) {
234		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
235		    sc->ld_ld->ld_secsize, virt, len)) != 0)
236			return (error);
237	} else {
238		/* mfi_sync_cache(parent_sc, sc->ld_id); */
239	}
240
241	return (0);
242}
243