mfi_disk.c revision 229611
154359Sroberto/*-
254359Sroberto * Copyright (c) 2006 IronPort Systems
354359Sroberto * All rights reserved.
454359Sroberto *
554359Sroberto * Redistribution and use in source and binary forms, with or without
654359Sroberto * modification, are permitted provided that the following conditions
754359Sroberto * are met:
854359Sroberto * 1. Redistributions of source code must retain the above copyright
954359Sroberto *    notice, this list of conditions and the following disclaimer.
1054359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1154359Sroberto *    notice, this list of conditions and the following disclaimer in the
1254359Sroberto *    documentation and/or other materials provided with the distribution.
1354359Sroberto *
1454359Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1554359Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1654359Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1754359Sroberto * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1854359Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1954359Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2054359Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2154359Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2254359Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2356746Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2456746Sroberto * SUCH DAMAGE.
2556746Sroberto */
2654359Sroberto
2754359Sroberto#include <sys/cdefs.h>
2854359Sroberto__FBSDID("$FreeBSD: stable/9/sys/dev/mfi/mfi_disk.c 229611 2012-01-05 18:30:48Z jhb $");
2954359Sroberto
3054359Sroberto#include "opt_mfi.h"
3154359Sroberto
3254359Sroberto#include <sys/param.h>
3354359Sroberto#include <sys/systm.h>
3454359Sroberto#include <sys/kernel.h>
3554359Sroberto#include <sys/selinfo.h>
3654359Sroberto#include <sys/module.h>
3754359Sroberto#include <sys/malloc.h>
3854359Sroberto#include <sys/sysctl.h>
3954359Sroberto#include <sys/uio.h>
4054359Sroberto
4154359Sroberto#include <sys/bio.h>
4254359Sroberto#include <sys/bus.h>
4354359Sroberto#include <sys/conf.h>
4454359Sroberto#include <sys/disk.h>
4554359Sroberto#include <geom/geom_disk.h>
4654359Sroberto
4756746Sroberto#include <vm/vm.h>
4856746Sroberto#include <vm/pmap.h>
4954359Sroberto
5056746Sroberto#include <machine/md_var.h>
5156746Sroberto#include <machine/bus.h>
5254359Sroberto#include <sys/rman.h>
5356746Sroberto
5456746Sroberto#include <dev/mfi/mfireg.h>
5554359Sroberto#include <dev/mfi/mfi_ioctl.h>
5656746Sroberto#include <dev/mfi/mfivar.h>
5756746Sroberto
5854359Srobertostatic int	mfi_disk_probe(device_t dev);
5956746Srobertostatic int	mfi_disk_attach(device_t dev);
6056746Srobertostatic int	mfi_disk_detach(device_t dev);
6154359Sroberto
6256746Srobertostatic disk_open_t	mfi_disk_open;
6356746Srobertostatic disk_close_t	mfi_disk_close;
6454359Srobertostatic disk_strategy_t	mfi_disk_strategy;
6554359Srobertostatic dumper_t		mfi_disk_dump;
6654359Sroberto
6754359Srobertostatic devclass_t	mfi_disk_devclass;
6854359Sroberto
6954359Srobertostatic device_method_t mfi_disk_methods[] = {
7054359Sroberto	DEVMETHOD(device_probe,		mfi_disk_probe),
7156746Sroberto	DEVMETHOD(device_attach,	mfi_disk_attach),
7256746Sroberto	DEVMETHOD(device_detach,	mfi_disk_detach),
7356746Sroberto	{ 0, 0 }
7482498Sroberto};
7582498Sroberto
7682498Srobertostatic driver_t mfi_disk_driver = {
7782498Sroberto	"mfid",
7882498Sroberto	mfi_disk_methods,
7982498Sroberto	sizeof(struct mfi_disk)
8054359Sroberto};
8154359Sroberto
8254359SrobertoDRIVER_MODULE(mfid, mfi, mfi_disk_driver, mfi_disk_devclass, 0, 0);
8354359Sroberto
8454359Srobertostatic int
8554359Srobertomfi_disk_probe(device_t dev)
8654359Sroberto{
8754359Sroberto
8854359Sroberto	return (0);
8954359Sroberto}
9054359Sroberto
9154359Srobertostatic int
9254359Srobertomfi_disk_attach(device_t dev)
9354359Sroberto{
9454359Sroberto	struct mfi_disk *sc;
9556746Sroberto	struct mfi_ld_info *ld_info;
9656746Sroberto	uint64_t sectors;
9756746Sroberto	uint32_t secsize;
9854359Sroberto	char *state;
9954359Sroberto
10054359Sroberto	sc = device_get_softc(dev);
10154359Sroberto	ld_info = device_get_ivars(dev);
10254359Sroberto
10354359Sroberto	sc->ld_dev = dev;
10454359Sroberto	sc->ld_id = ld_info->ld_config.properties.ld.v.target_id;
10554359Sroberto	sc->ld_unit = device_get_unit(dev);
10654359Sroberto	sc->ld_info = ld_info;
10756746Sroberto	sc->ld_controller = device_get_softc(device_get_parent(dev));
10856746Sroberto	sc->ld_flags = 0;
10956746Sroberto
11054359Sroberto	sectors = ld_info->size;
11154359Sroberto	secsize = MFI_SECTOR_LEN;
11254359Sroberto	mtx_lock(&sc->ld_controller->mfi_io_lock);
11354359Sroberto	TAILQ_INSERT_TAIL(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
11454359Sroberto	mtx_unlock(&sc->ld_controller->mfi_io_lock);
11554359Sroberto
11656746Sroberto	switch (ld_info->ld_config.params.state) {
11756746Sroberto	case MFI_LD_STATE_OFFLINE:
11854359Sroberto		state = "offline";
11954359Sroberto		break;
12054359Sroberto	case MFI_LD_STATE_PARTIALLY_DEGRADED:
12154359Sroberto		state = "partially degraded";
12254359Sroberto		break;
12354359Sroberto	case MFI_LD_STATE_DEGRADED:
12454359Sroberto		state = "degraded";
12554359Sroberto		break;
12654359Sroberto	case MFI_LD_STATE_OPTIMAL:
12754359Sroberto		state = "optimal";
12856746Sroberto		break;
12956746Sroberto	default:
13056746Sroberto		state = "unknown";
13156746Sroberto		break;
13256746Sroberto	}
13356746Sroberto	device_printf(dev, "%juMB (%ju sectors) RAID volume '%s' is %s\n",
13456746Sroberto		      sectors / (1024 * 1024 / secsize), sectors,
13556746Sroberto		      ld_info->ld_config.properties.name,
13656746Sroberto		      state);
13754359Sroberto
13854359Sroberto	sc->ld_disk = disk_alloc();
13954359Sroberto	sc->ld_disk->d_drv1 = sc;
14056746Sroberto	sc->ld_disk->d_maxsize = min(sc->ld_controller->mfi_max_io * secsize,
14156746Sroberto	    (sc->ld_controller->mfi_max_sge - 1) * PAGE_SIZE);
14254359Sroberto	sc->ld_disk->d_name = "mfid";
14354359Sroberto	sc->ld_disk->d_open = mfi_disk_open;
14454359Sroberto	sc->ld_disk->d_close = mfi_disk_close;
14554359Sroberto	sc->ld_disk->d_strategy = mfi_disk_strategy;
14654359Sroberto	sc->ld_disk->d_dump = mfi_disk_dump;
14754359Sroberto	sc->ld_disk->d_unit = sc->ld_unit;
14854359Sroberto	sc->ld_disk->d_sectorsize = secsize;
14956746Sroberto	sc->ld_disk->d_mediasize = sectors * secsize;
15056746Sroberto	if (sc->ld_disk->d_mediasize >= (1 * 1024 * 1024)) {
15156746Sroberto		sc->ld_disk->d_fwheads = 255;
15256746Sroberto		sc->ld_disk->d_fwsectors = 63;
15356746Sroberto	} else {
15456746Sroberto		sc->ld_disk->d_fwheads = 64;
15554359Sroberto		sc->ld_disk->d_fwsectors = 32;
15654359Sroberto	}
15754359Sroberto	disk_create(sc->ld_disk, DISK_VERSION);
15856746Sroberto
15956746Sroberto	return (0);
16056746Sroberto}
16154359Sroberto
16254359Srobertostatic int
16354359Srobertomfi_disk_detach(device_t dev)
16456746Sroberto{
16556746Sroberto	struct mfi_disk *sc;
16654359Sroberto
16756746Sroberto	sc = device_get_softc(dev);
16856746Sroberto
16954359Sroberto	mtx_lock(&sc->ld_controller->mfi_io_lock);
17056746Sroberto	if (((sc->ld_disk->d_flags & DISKFLAG_OPEN) ||
17156746Sroberto	    (sc->ld_flags & MFI_DISK_FLAGS_OPEN)) &&
17254359Sroberto	    (sc->ld_controller->mfi_keep_deleted_volumes ||
17354359Sroberto	    sc->ld_controller->mfi_detaching)) {
17454359Sroberto		mtx_unlock(&sc->ld_controller->mfi_io_lock);
17554359Sroberto		return (EBUSY);
17654359Sroberto	}
17754359Sroberto	mtx_unlock(&sc->ld_controller->mfi_io_lock);
17854359Sroberto
17954359Sroberto	disk_destroy(sc->ld_disk);
18054359Sroberto	mtx_lock(&sc->ld_controller->mfi_io_lock);
18154359Sroberto	TAILQ_REMOVE(&sc->ld_controller->mfi_ld_tqh, sc, ld_link);
18254359Sroberto	mtx_unlock(&sc->ld_controller->mfi_io_lock);
18354359Sroberto	free(sc->ld_info, M_MFIBUF);
18454359Sroberto	return (0);
18554359Sroberto}
18654359Sroberto
18754359Srobertostatic int
18854359Srobertomfi_disk_open(struct disk *dp)
18954359Sroberto{
19054359Sroberto	struct mfi_disk *sc;
19154359Sroberto	int error;
19254359Sroberto
19354359Sroberto	sc = dp->d_drv1;
19454359Sroberto	mtx_lock(&sc->ld_controller->mfi_io_lock);
19554359Sroberto	if (sc->ld_flags & MFI_DISK_FLAGS_DISABLED)
19654359Sroberto		error = ENXIO;
19754359Sroberto	else {
19854359Sroberto		sc->ld_flags |= MFI_DISK_FLAGS_OPEN;
19954359Sroberto		error = 0;
20054359Sroberto	}
20154359Sroberto	mtx_unlock(&sc->ld_controller->mfi_io_lock);
20254359Sroberto
20354359Sroberto	return (error);
20454359Sroberto}
20554359Sroberto
20654359Srobertostatic int
20754359Srobertomfi_disk_close(struct disk *dp)
20854359Sroberto{
20954359Sroberto	struct mfi_disk *sc;
21054359Sroberto
21154359Sroberto	sc = dp->d_drv1;
21254359Sroberto	mtx_lock(&sc->ld_controller->mfi_io_lock);
21354359Sroberto	sc->ld_flags &= ~MFI_DISK_FLAGS_OPEN;
21454359Sroberto	mtx_unlock(&sc->ld_controller->mfi_io_lock);
21554359Sroberto
21654359Sroberto	return (0);
21754359Sroberto}
21854359Sroberto
21954359Srobertoint
22054359Srobertomfi_disk_disable(struct mfi_disk *sc)
22154359Sroberto{
22254359Sroberto
22354359Sroberto	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
22454359Sroberto	if (sc->ld_flags & MFI_DISK_FLAGS_OPEN) {
22554359Sroberto		if (sc->ld_controller->mfi_delete_busy_volumes)
22654359Sroberto			return (0);
22754359Sroberto		device_printf(sc->ld_dev, "Unable to delete busy device\n");
22854359Sroberto		return (EBUSY);
22954359Sroberto	}
23054359Sroberto	sc->ld_flags |= MFI_DISK_FLAGS_DISABLED;
23154359Sroberto	return (0);
23254359Sroberto}
23354359Sroberto
23454359Srobertovoid
23554359Srobertomfi_disk_enable(struct mfi_disk *sc)
23654359Sroberto{
23754359Sroberto
23854359Sroberto	mtx_assert(&sc->ld_controller->mfi_io_lock, MA_OWNED);
23954359Sroberto	sc->ld_flags &= ~MFI_DISK_FLAGS_DISABLED;
24054359Sroberto}
24154359Sroberto
24254359Srobertostatic void
24354359Srobertomfi_disk_strategy(struct bio *bio)
24454359Sroberto{
24554359Sroberto	struct mfi_disk *sc;
24654359Sroberto	struct mfi_softc *controller;
24754359Sroberto
24854359Sroberto	sc = bio->bio_disk->d_drv1;
24954359Sroberto
25054359Sroberto	if (sc == NULL) {
25154359Sroberto		bio->bio_error = EINVAL;
25254359Sroberto		bio->bio_flags |= BIO_ERROR;
25354359Sroberto		bio->bio_resid = bio->bio_bcount;
25454359Sroberto		biodone(bio);
25554359Sroberto		return;
25654359Sroberto	}
25754359Sroberto
25854359Sroberto	controller = sc->ld_controller;
25954359Sroberto	bio->bio_driver1 = (void *)(uintptr_t)sc->ld_id;
26054359Sroberto	mtx_lock(&controller->mfi_io_lock);
26154359Sroberto	mfi_enqueue_bio(controller, bio);
26254359Sroberto	mfi_startio(controller);
26354359Sroberto	mtx_unlock(&controller->mfi_io_lock);
26454359Sroberto	return;
26554359Sroberto}
26654359Sroberto
26754359Srobertovoid
26854359Srobertomfi_disk_complete(struct bio *bio)
26954359Sroberto{
27054359Sroberto	struct mfi_disk *sc;
27154359Sroberto	struct mfi_frame_header *hdr;
27282498Sroberto
27382498Sroberto	sc = bio->bio_disk->d_drv1;
27482498Sroberto	hdr = bio->bio_driver1;
27554359Sroberto
27654359Sroberto	if (bio->bio_flags & BIO_ERROR) {
27754359Sroberto		if (bio->bio_error == 0)
27854359Sroberto			bio->bio_error = EIO;
27954359Sroberto		disk_err(bio, "hard error", -1, 1);
28054359Sroberto	} else {
28154359Sroberto		bio->bio_resid = 0;
28254359Sroberto	}
28354359Sroberto	biodone(bio);
28454359Sroberto}
28554359Sroberto
28654359Srobertostatic int
28754359Srobertomfi_disk_dump(void *arg, void *virt, vm_offset_t phys, off_t offset, size_t len)
28854359Sroberto{
28954359Sroberto	struct mfi_disk *sc;
29054359Sroberto	struct mfi_softc *parent_sc;
29154359Sroberto	struct disk *dp;
29254359Sroberto	int error;
29354359Sroberto
29454359Sroberto	dp = arg;
29554359Sroberto	sc = dp->d_drv1;
29654359Sroberto	parent_sc = sc->ld_controller;
29754359Sroberto
29854359Sroberto	if (len > 0) {
29954359Sroberto		if ((error = mfi_dump_blocks(parent_sc, sc->ld_id, offset /
30054359Sroberto		    MFI_SECTOR_LEN, virt, len)) != 0)
30154359Sroberto			return (error);
30282498Sroberto	} else {
30382498Sroberto		/* mfi_sync_cache(parent_sc, sc->ld_id); */
30482498Sroberto	}
30554359Sroberto
30654359Sroberto	return (0);
30754359Sroberto}
30854359Sroberto