mfi_disk.c revision 243824
1251876Speter/*-
2251876Speter * Copyright (c) 2006 IronPort Systems
3251876Speter * All rights reserved.
4251876Speter *
5251876Speter * Redistribution and use in source and binary forms, with or without
6251876Speter * modification, are permitted provided that the following conditions
7251876Speter * are met:
8251876Speter * 1. Redistributions of source code must retain the above copyright
9251876Speter *    notice, this list of conditions and the following disclaimer.
10253734Speter * 2. Redistributions in binary form must reproduce the above copyright
11251876Speter *    notice, this list of conditions and the following disclaimer in the
12251876Speter *    documentation and/or other materials provided with the distribution.
13251876Speter *
14251876Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15251876Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16251876Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17251876Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18251876Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19251876Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20251876Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21251876Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22251876Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23251876Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24251876Speter * SUCH DAMAGE.
25251876Speter */
26251876Speter
27251876Speter#include <sys/cdefs.h>
28251876Speter__FBSDID("$FreeBSD: stable/9/sys/dev/mfi/mfi_disk.c 243824 2012-12-03 18:37:02Z delphij $");
29251876Speter
30251876Speter#include "opt_mfi.h"
31251876Speter
32251876Speter#include <sys/param.h>
33251876Speter#include <sys/systm.h>
34251876Speter#include <sys/kernel.h>
35251876Speter#include <sys/selinfo.h>
36251876Speter#include <sys/module.h>
37251876Speter#include <sys/malloc.h>
38251876Speter#include <sys/sysctl.h>
39251876Speter#include <sys/uio.h>
40251876Speter
41251876Speter#include <sys/bio.h>
42251876Speter#include <sys/bus.h>
43251876Speter#include <sys/conf.h>
44251876Speter#include <sys/disk.h>
45251876Speter#include <geom/geom_disk.h>
46251876Speter
47251876Speter#include <vm/vm.h>
48251876Speter#include <vm/pmap.h>
49251876Speter
50251876Speter#include <machine/md_var.h>
51251876Speter#include <machine/bus.h>
52251876Speter#include <sys/rman.h>
53251876Speter
54251876Speter#include <dev/mfi/mfireg.h>
55251876Speter#include <dev/mfi/mfi_ioctl.h>
56251876Speter#include <dev/mfi/mfivar.h>
57251876Speter
58251876Speterstatic int	mfi_disk_probe(device_t dev);
59251876Speterstatic int	mfi_disk_attach(device_t dev);
60251876Speterstatic int	mfi_disk_detach(device_t dev);
61251876Speter
62251876Speterstatic disk_open_t	mfi_disk_open;
63251876Speterstatic disk_close_t	mfi_disk_close;
64251876Speterstatic disk_strategy_t	mfi_disk_strategy;
65251876Speterstatic dumper_t		mfi_disk_dump;
66251876Speter
67251876Speterstatic devclass_t	mfi_disk_devclass;
68251876Speter
69251876Speterstatic device_method_t mfi_disk_methods[] = {
70251876Speter	DEVMETHOD(device_probe,		mfi_disk_probe),
71251876Speter	DEVMETHOD(device_attach,	mfi_disk_attach),
72251876Speter	DEVMETHOD(device_detach,	mfi_disk_detach),
73251876Speter	{ 0, 0 }
74251876Speter};
75251876Speter
76251876Speterstatic driver_t mfi_disk_driver = {
77251876Speter	"mfid",
78251876Speter	mfi_disk_methods,
79251876Speter	sizeof(struct mfi_disk)
80251876Speter};
81251876Speter
82251876SpeterDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
83251876Speter
84251876Speterstatic int
85251876Spetermfi_disk_probe(device_t dev)
86251876Speter{
87251876Speter
88251876Speter	return (0);
89251876Speter}
90251876Speter
91251876Speterstatic int
92251876Spetermfi_disk_attach(device_t dev)
93251876Speter{
94251876Speter	struct mfi_disk *sc;
95251876Speter	struct mfi_ld_info *ld_info;
96251876Speter	struct mfi_disk_pending *ld_pend;
97251876Speter	uint64_t sectors;
98251876Speter	uint32_t secsize;
99251876Speter	char *state;
100251876Speter
101251876Speter	sc = device_get_softc(dev);
102251876Speter	ld_info = device_get_ivars(dev);
103251876Speter
104251876Speter	sc->ld_dev = dev;
105251876Speter	sc->ld_id = ld_info->ld_config.properties.ld.v.target_id;
106251876Speter	sc->ld_unit = device_get_unit(dev);
107251876Speter	sc->ld_info = ld_info;
108251876Speter	sc->ld_controller = device_get_softc(device_get_parent(dev));
109251876Speter	sc->ld_flags = 0;
110251876Speter
111251876Speter	sectors = ld_info->size;
112251876Speter	secsize = MFI_SECTOR_LEN;
113251876Speter	mtx_lock(&sc->ld_controller->mfi_io_lock);
114251876Speter	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
115251876Speter	TAILQ_FOREACH(ld_pend, &sc->ld_controller->mfi_ld_pend_tqh,
116251876Speter	    ld_link) {
117251876Speter		TAILQ_REMOVE(&sc->ld_controller->mfi_ld_pend_tqh,
118251876Speter		    ld_pend, ld_link);
119251876Speter		free(ld_pend, M_MFIBUF);
120251876Speter		break;
121251876Speter	}
122251876Speter	mtx_unlock(&sc->ld_controller->mfi_io_lock);
123251876Speter
124251876Speter	switch (ld_info->ld_config.params.state) {
125251876Speter	case MFI_LD_STATE_OFFLINE:
126251876Speter		state = "offline";
127251876Speter		break;
128251876Speter	case MFI_LD_STATE_PARTIALLY_DEGRADED:
129251876Speter		state = "partially degraded";
130251876Speter		break;
131251876Speter	case MFI_LD_STATE_DEGRADED:
132251876Speter		state = "degraded";
133251876Speter		break;
134251876Speter	case MFI_LD_STATE_OPTIMAL:
135251876Speter		state = "optimal";
136251876Speter		break;
137251876Speter	default:
138251876Speter		state = "unknown";
139251876Speter		break;
140251876Speter	}
141251876Speter
142251876Speter	if ( strlen(ld_info->ld_config.properties.name) == 0 ) {
143251876Speter		device_printf(dev,
144251876Speter		      "%juMB (%ju sectors) RAID volume (no label) is %s\n",
145251876Speter		       sectors / (1024 * 1024 / secsize), sectors, state);
146251876Speter	} else {
147251876Speter		device_printf(dev,
148251876Speter		      "%juMB (%ju sectors) RAID volume '%s' is %s\n",
149251876Speter		      sectors / (1024 * 1024 / secsize), sectors,
150251876Speter		      ld_info->ld_config.properties.name, state);
151251876Speter	}
152251876Speter
153251876Speter	sc->ld_disk = disk_alloc();
154251876Speter	sc->ld_disk->d_drv1 = sc;
155251876Speter	sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize,
156251876Speter	    (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE);
157251876Speter	sc->ld_disk->d_name = "mfid";
158251876Speter	sc->ld_disk->d_open = mfi_disk_open;
159251876Speter	sc->ld_disk->d_close = mfi_disk_close;
160251876Speter	sc->ld_disk->d_strategy = mfi_disk_strategy;
161251876Speter	sc->ld_disk->d_dump = mfi_disk_dump;
162251876Speter	sc->ld_disk->d_unit = sc->ld_unit;
163251876Speter	sc->ld_disk->d_sectorsize = secsize;
164251876Speter	sc->ld_disk->d_mediasize = sectors * secsize;
165251876Speter	if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) {
166251876Speter		sc->ld_disk->d_fwheads = 255;
167251876Speter		sc->ld_disk->d_fwsectors = 63;
168251876Speter	} else {
169251876Speter		sc->ld_disk->d_fwheads = 64;
170251876Speter		sc->ld_disk->d_fwsectors = 32;
171251876Speter	}
172251876Speter	disk_create(sc->ld_disk, DISK_VERSION);
173251876Speter
174251876Speter	return (0);
175251876Speter}
176251876Speter
177251876Speterstatic int
178251876Spetermfi_disk_detach(device_t dev)
179251876Speter{
180251876Speter	struct mfi_disk *sc;
181251876Speter
182251876Speter	sc = device_get_softc(dev);
183251876Speter
184251876Speter	mtx_lock(&sc->ld_controller->mfi_io_lock);
185251876Speter	if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) ||
186251876Speter	    (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
187251876Speter	    (sc->ld_controller->mfi_keep_deleted_volumes ||
188251876Speter	    sc->ld_controller->mfi_detaching)) {
189251876Speter		mtx_unlock(&sc->ld_controller->mfi_io_lock);
190251876Speter		return (EBUSY);
191251876Speter	}
192251876Speter	mtx_unlock(&sc->ld_controller->mfi_io_lock);
193251876Speter
194251876Speter	disk_destroy(sc->ld_disk);
195251876Speter	mtx_lock(&sc->ld_controller->mfi_io_lock);
196251876Speter	TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
197251876Speter	mtx_unlock(&sc->ld_controller->mfi_io_lock);
198251876Speter	free(sc->ld_info, M_MFIBUF);
199251876Speter	return (0);
200251876Speter}
201251876Speter
202251876Speterstatic int
203251876Spetermfi_disk_open(struct disk *dp)
204251876Speter{
205251876Speter	struct mfi_disk *sc;
206251876Speter	int error;
207251876Speter
208251876Speter	sc = dp->d_drv1;
209251876Speter	mtx_lock(&sc->ld_controller->mfi_io_lock);
210251876Speter	if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED)
211251876Speter		error = ENXIO;
212251876Speter	else {
213251876Speter		sc->ld_flags |= MFI_DISK_FLAGS_OPEN;
214251876Speter		error = 0;
215251876Speter	}
216251876Speter	mtx_unlock(&sc->ld_controller->mfi_io_lock);
217251876Speter
218251876Speter	return (error);
219251876Speter}
220251876Speter
221251876Speterstatic int
222251876Spetermfi_disk_close(struct disk *dp)
223251876Speter{
224251876Speter	struct mfi_disk *sc;
225251876Speter
226251876Speter	sc = dp->d_drv1;
227251876Speter	mtx_lock(&sc->ld_controller->mfi_io_lock);
228251876Speter	sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN;
229251876Speter	mtx_unlock(&sc->ld_controller->mfi_io_lock);
230251876Speter
231251876Speter	return (0);
232251876Speter}
233251876Speter
234251876Speterint
235251876Spetermfi_disk_disable(struct mfi_disk *sc)
236251876Speter{
237251876Speter
238251876Speter	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
239251876Speter	if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
240251876Speter		if (sc->ld_controller->mfi_delete_busy_volumes)
241251876Speter			return (0);
242251876Speter		device_printf(sc->ld_dev, "Unable to delete busy ld device\n");
243251876Speter		return (EBUSY);
244251876Speter	}
245251876Speter	sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
246251876Speter	return (0);
247251876Speter}
248251876Speter
249251876Spetervoid
250251876Spetermfi_disk_enable(struct mfi_disk *sc)
251251876Speter{
252251876Speter
253251876Speter	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
254251876Speter	sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED;
255251876Speter}
256251876Speter
257251876Speterstatic void
258251876Spetermfi_disk_strategy(struct bio *bio)
259251876Speter{
260251876Speter	struct mfi_disk *sc;
261251876Speter	struct mfi_softc *controller;
262251876Speter
263251876Speter	sc = bio->bio_disk->d_drv1;
264251876Speter	controller = sc->ld_controller;
265251876Speter
266251876Speter	if (sc == NULL) {
267251876Speter		bio->bio_error = EINVAL;
268251876Speter		bio->bio_flags |= BIO_ERROR;
269251876Speter		bio->bio_resid = bio->bio_bcount;
270251876Speter		biodone(bio);
271251876Speter		return;
272251876Speter	}
273251876Speter
274251876Speter	if (controller->adpreset) {
275251876Speter		bio->bio_error = EBUSY;
276251876Speter		return;
277251876Speter	}
278251876Speter
279251876Speter	if (controller->hw_crit_error) {
280251876Speter		bio->bio_error = EBUSY;
281251876Speter		return;
282251876Speter	}
283251876Speter
284251876Speter	if (controller->issuepend_done == 0) {
285251876Speter		bio->bio_error = EBUSY;
286251876Speter		return;
287251876Speter	}
288251876Speter
289251876Speter	bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
290251876Speter	/* Mark it as LD IO */
291251876Speter	bio->bio_driver2 = (void *)MFI_LD_IO;
292251876Speter	mtx_lock(&controller->mfi_io_lock);
293251876Speter	mfi_enqueue_bio(controller, bio);
294251876Speter	mfi_startio(controller);
295251876Speter	mtx_unlock(&controller->mfi_io_lock);
296251876Speter	return;
297251876Speter}
298251876Speter
299251876Spetervoid
300251876Spetermfi_disk_complete(struct bio *bio)
301251876Speter{
302251876Speter	struct mfi_disk *sc;
303251876Speter	struct mfi_frame_header *hdr;
304251876Speter
305251876Speter	sc = bio->bio_disk->d_drv1;
306251876Speter	hdr = bio->bio_driver1;
307251876Speter
308251876Speter	if (bio->bio_flags & BIO_ERROR) {
309251876Speter		bio->bio_resid = bio->bio_bcount;
310251876Speter		if (bio->bio_error == 0)
311251876Speter			bio->bio_error = EIO;
312251876Speter		disk_err(bio, "hard error", -1, 1);
313251876Speter	} else {
314251876Speter		bio->bio_resid = 0;
315251876Speter	}
316251876Speter	biodone(bio);
317251876Speter}
318251876Speter
319251876Speterstatic int
320251876Spetermfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
321251876Speter{
322251876Speter	struct mfi_disk *sc;
323251876Speter	struct mfi_softc *parent_sc;
324251876Speter	struct disk *dp;
325251876Speter	int error;
326251876Speter
327251876Speter	dp = arg;
328251876Speter	sc = dp->d_drv1;
329251876Speter	parent_sc = sc->ld_controller;
330251876Speter
331251876Speter	if (len > 0) {
332251876Speter		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
333251876Speter		    MFI_SECTOR_LEN, virt, len)) != 0)
334251876Speter			return (error);
335251876Speter	} else {
336251876Speter		/* mfi_sync_cache(parent_sc, sc->ld_id); */
337251876Speter	}
338251876Speter
339251876Speter	return (0);
340251876Speter}
341251876Speter