amr_disk.c revision 111249
151974Smsmith/*-
251974Smsmith * Copyright (c) 1999 Jonathan Lemon
365245Smsmith * Copyright (c) 1999, 2000 Michael Smith
465245Smsmith * Copyright (c) 2000 BSDi
551974Smsmith * All rights reserved.
651974Smsmith *
751974Smsmith * Redistribution and use in source and binary forms, with or without
851974Smsmith * modification, are permitted provided that the following conditions
951974Smsmith * are met:
1051974Smsmith * 1. Redistributions of source code must retain the above copyright
1151974Smsmith *    notice, this list of conditions and the following disclaimer.
1251974Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1351974Smsmith *    notice, this list of conditions and the following disclaimer in the
1451974Smsmith *    documentation and/or other materials provided with the distribution.
1551974Smsmith *
1651974Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1751974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1851974Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1951974Smsmith * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2051974Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2151974Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2251974Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2351974Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2451974Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2551974Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2651974Smsmith * SUCH DAMAGE.
2751974Smsmith *
28106225Semoore * Copyright (c) 2002 Eric Moore
29106225Semoore * Copyright (c) 2002 LSI Logic Corporation
30106225Semoore * All rights reserved.
31106225Semoore *
32106225Semoore * Redistribution and use in source and binary forms, with or without
33106225Semoore * modification, are permitted provided that the following conditions
34106225Semoore * are met:
35106225Semoore * 1. Redistributions of source code must retain the above copyright
36106225Semoore *    notice, this list of conditions and the following disclaimer.
37106225Semoore * 2. Redistributions in binary form must reproduce the above copyright
38106225Semoore *    notice, this list of conditions and the following disclaimer in the
39106225Semoore *    documentation and/or other materials provided with the distribution.
40105419Semoore * 3. The party using or redistributing the source code and binary forms
41106225Semoore *    agrees to the disclaimer below and the terms and conditions set forth
42105419Semoore *    herein.
43105419Semoore *
44106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47106225Semoore * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54106225Semoore * SUCH DAMAGE.
55105419Semoore *
56106225Semoore *
5751974Smsmith * $FreeBSD: head/sys/dev/amr/amr_disk.c 111249 2003-02-22 10:02:05Z phk $
5851974Smsmith */
5951974Smsmith
6051974Smsmith/*
6151974Smsmith * Disk driver for AMI MegaRaid controllers
6251974Smsmith */
6351974Smsmith
6451974Smsmith#include <sys/param.h>
6551974Smsmith#include <sys/systm.h>
6651974Smsmith#include <sys/kernel.h>
6751974Smsmith
6865245Smsmith#include <dev/amr/amr_compat.h>
6951974Smsmith#include <sys/bus.h>
7051974Smsmith#include <sys/conf.h>
7151974Smsmith#include <sys/devicestat.h>
7251974Smsmith#include <sys/disk.h>
7351974Smsmith
7451974Smsmith#include <machine/bus.h>
7551974Smsmith#include <sys/rman.h>
7651974Smsmith
7751974Smsmith#include <dev/amr/amrio.h>
7851974Smsmith#include <dev/amr/amrreg.h>
7951974Smsmith#include <dev/amr/amrvar.h>
8065245Smsmith#include <dev/amr/amr_tables.h>
8151974Smsmith
8251974Smsmith/* prototypes */
8351974Smsmithstatic int amrd_probe(device_t dev);
8451974Smsmithstatic int amrd_attach(device_t dev);
8551974Smsmithstatic int amrd_detach(device_t dev);
8651974Smsmith
8751974Smsmithstatic	d_open_t	amrd_open;
8851974Smsmithstatic	d_close_t	amrd_close;
8951974Smsmithstatic	d_strategy_t	amrd_strategy;
9051974Smsmith
9151974Smsmith#define AMRD_CDEV_MAJOR	133
9251974Smsmith
9351974Smsmithstatic struct cdevsw amrd_cdevsw = {
9451974Smsmith		/* open */	amrd_open,
9551974Smsmith		/* close */	amrd_close,
9651974Smsmith		/* read */	physread,
9751974Smsmith		/* write */	physwrite,
98111249Sphk		/* ioctl */	noioctl,
9951974Smsmith		/* poll */	nopoll,
10051974Smsmith		/* mmap */	nommap,
10151974Smsmith		/* strategy */	amrd_strategy,
10251974Smsmith		/* name */ 	"amrd",
10351974Smsmith		/* maj */	AMRD_CDEV_MAJOR,
10451974Smsmith		/* dump */	nodump,
10551974Smsmith		/* psize */ 	nopsize,
10651974Smsmith		/* flags */	D_DISK,
107107756Semoore#if __FreeBSD_version < 500000
108107756Semoore		/* bmaj */	-1
109107756Semoore#endif
11051974Smsmith};
11151974Smsmith
11251974Smsmithstatic devclass_t	amrd_devclass;
11351974Smsmithstatic struct cdevsw	amrddisk_cdevsw;
11465245Smsmith#ifdef FREEBSD_4
11551974Smsmithstatic int		disks_registered = 0;
11665245Smsmith#endif
11751974Smsmith
11851974Smsmithstatic device_method_t amrd_methods[] = {
11951974Smsmith    DEVMETHOD(device_probe,	amrd_probe),
12051974Smsmith    DEVMETHOD(device_attach,	amrd_attach),
12151974Smsmith    DEVMETHOD(device_detach,	amrd_detach),
12251974Smsmith    { 0, 0 }
12351974Smsmith};
12451974Smsmith
12551974Smsmithstatic driver_t amrd_driver = {
12651974Smsmith    "amrd",
12751974Smsmith    amrd_methods,
12851974Smsmith    sizeof(struct amrd_softc)
12951974Smsmith};
13051974Smsmith
13151974SmsmithDRIVER_MODULE(amrd, amr, amrd_driver, amrd_devclass, 0, 0);
13251974Smsmith
13351974Smsmithstatic int
134105419Semooreamrd_open(dev_t dev, int flags, int fmt, d_thread_t *td)
13551974Smsmith{
13658883Smsmith    struct amrd_softc	*sc = (struct amrd_softc *)dev->si_drv1;
137105419Semoore#if __FreeBSD_version < 500000		/* old buf style */
138105419Semoore    struct disklabel    *label;
139105419Semoore#endif
14051974Smsmith
14165245Smsmith    debug_called(1);
142105419Semoore
14351974Smsmith    if (sc == NULL)
14451974Smsmith	return (ENXIO);
14551974Smsmith
14651974Smsmith    /* controller not active? */
14751974Smsmith    if (sc->amrd_controller->amr_state & AMR_STATE_SHUTDOWN)
14851974Smsmith	return(ENXIO);
14951974Smsmith
150105419Semoore#if __FreeBSD_version < 500000		/* old buf style */
151105419Semoore    label = &sc->amrd_disk.d_label;
152105419Semoore    bzero(label, sizeof(*label));
153105419Semoore    label->d_type       = DTYPE_SCSI;
154105419Semoore    label->d_secsize    = AMR_BLKSIZE;
155105419Semoore    label->d_nsectors   = sc->amrd_drive->al_sectors;
156105419Semoore    label->d_ntracks    = sc->amrd_drive->al_heads;
157105419Semoore    label->d_ncylinders = sc->amrd_drive->al_cylinders;
158105419Semoore    label->d_secpercyl  = sc->amrd_drive->al_sectors * sc->amrd_drive->al_heads;
159105419Semoore    label->d_secperunit = sc->amrd_drive->al_size;
160105419Semoore#else
161103714Sphk    sc->amrd_disk.d_sectorsize = AMR_BLKSIZE;
162103714Sphk    sc->amrd_disk.d_mediasize = (off_t)sc->amrd_drive->al_size * AMR_BLKSIZE;
163103714Sphk    sc->amrd_disk.d_fwsectors = sc->amrd_drive->al_sectors;
164103714Sphk    sc->amrd_disk.d_fwheads = sc->amrd_drive->al_heads;
165105419Semoore#endif
16651974Smsmith
16751974Smsmith    sc->amrd_flags |= AMRD_OPEN;
16851974Smsmith    return (0);
16951974Smsmith}
17051974Smsmith
17151974Smsmithstatic int
172105419Semooreamrd_close(dev_t dev, int flags, int fmt, d_thread_t *td)
17351974Smsmith{
17458883Smsmith    struct amrd_softc	*sc = (struct amrd_softc *)dev->si_drv1;
17551974Smsmith
17665245Smsmith    debug_called(1);
177105419Semoore
17851974Smsmith    if (sc == NULL)
17951974Smsmith	return (ENXIO);
18051974Smsmith    sc->amrd_flags &= ~AMRD_OPEN;
18151974Smsmith    return (0);
18251974Smsmith}
18351974Smsmith
18451974Smsmith/*
18551974Smsmith * Read/write routine for a buffer.  Finds the proper unit, range checks
18651974Smsmith * arguments, and schedules the transfer.  Does not wait for the transfer
18751974Smsmith * to complete.  Multi-page transfers are supported.  All I/O requests must
18851974Smsmith * be a multiple of a sector in length.
18951974Smsmith */
19051974Smsmithstatic void
19165245Smsmithamrd_strategy(struct bio *bio)
19251974Smsmith{
19365245Smsmith    struct amrd_softc	*sc = (struct amrd_softc *)bio->bio_dev->si_drv1;
19451974Smsmith
19551974Smsmith    /* bogus disk? */
19651974Smsmith    if (sc == NULL) {
19765245Smsmith	bio->bio_error = EINVAL;
19851974Smsmith	goto bad;
19951974Smsmith    }
20051974Smsmith
20151974Smsmith    devstat_start_transaction(&sc->amrd_stats);
20265245Smsmith    amr_submit_bio(sc->amrd_controller, bio);
20351974Smsmith    return;
20451974Smsmith
20551974Smsmith bad:
20665245Smsmith    bio->bio_flags |= BIO_ERROR;
20751974Smsmith
20851974Smsmith    /*
20951974Smsmith     * Correctly set the buf to indicate a completed transfer
21051974Smsmith     */
21165245Smsmith    bio->bio_resid = bio->bio_bcount;
21265245Smsmith    biodone(bio);
21351974Smsmith    return;
21451974Smsmith}
21551974Smsmith
21651974Smsmithvoid
21751974Smsmithamrd_intr(void *data)
21851974Smsmith{
21965245Smsmith    struct bio *bio = (struct bio *)data;
22065245Smsmith    struct amrd_softc *sc = (struct amrd_softc *)bio->bio_dev->si_drv1;
22151974Smsmith
22265245Smsmith    debug_called(2);
22358883Smsmith
22465245Smsmith    if (bio->bio_flags & BIO_ERROR) {
22565245Smsmith	bio->bio_error = EIO;
22665245Smsmith	debug(1, "i/o error\n");
22758883Smsmith    } else {
22865245Smsmith	bio->bio_resid = 0;
22958883Smsmith    }
23051974Smsmith
231105419Semoore    AMR_BIO_FINISH(bio);
23251974Smsmith}
23351974Smsmith
23451974Smsmithstatic int
23551974Smsmithamrd_probe(device_t dev)
23651974Smsmith{
23751974Smsmith
23865245Smsmith    debug_called(1);
239105419Semoore
240105419Semoore    device_set_desc(dev, "LSILogic MegaRAID logical drive");
24151974Smsmith    return (0);
24251974Smsmith}
24351974Smsmith
24451974Smsmithstatic int
24551974Smsmithamrd_attach(device_t dev)
24651974Smsmith{
24751974Smsmith    struct amrd_softc	*sc = (struct amrd_softc *)device_get_softc(dev);
24851974Smsmith    device_t		parent;
24951974Smsmith
25065245Smsmith    debug_called(1);
25151974Smsmith
25251974Smsmith    parent = device_get_parent(dev);
25351974Smsmith    sc->amrd_controller = (struct amr_softc *)device_get_softc(parent);
25451974Smsmith    sc->amrd_unit = device_get_unit(dev);
25551974Smsmith    sc->amrd_drive = device_get_ivars(dev);
25652274Smsmith    sc->amrd_dev = dev;
25751974Smsmith
25852784Smsmith    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
25951974Smsmith		  sc->amrd_drive->al_size / ((1024 * 1024) / AMR_BLKSIZE),
26065245Smsmith		  sc->amrd_drive->al_size, sc->amrd_drive->al_properties & AMR_DRV_RAID_MASK,
26165245Smsmith		  amr_describe_code(amr_table_drvstate, AMR_DRV_CURSTATE(sc->amrd_drive->al_state)));
26251974Smsmith
26351974Smsmith    devstat_add_entry(&sc->amrd_stats, "amrd", sc->amrd_unit, AMR_BLKSIZE,
26451974Smsmith		      DEVSTAT_NO_ORDERED_TAGS,
26554279Sken		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
26654279Sken		      DEVSTAT_PRIORITY_ARRAY);
26751974Smsmith
26858883Smsmith    sc->amrd_dev_t = disk_create(sc->amrd_unit, &sc->amrd_disk, 0, &amrd_cdevsw, &amrddisk_cdevsw);
26958883Smsmith    sc->amrd_dev_t->si_drv1 = sc;
27065245Smsmith#ifdef FREEBSD_4
27151974Smsmith    disks_registered++;
27265245Smsmith#endif
27351974Smsmith
27465245Smsmith    /* set maximum I/O size to match the maximum s/g size */
27565245Smsmith    sc->amrd_dev_t->si_iosize_max = (AMR_NSEG - 1) * PAGE_SIZE;
27658883Smsmith
27751974Smsmith    return (0);
27851974Smsmith}
27951974Smsmith
28051974Smsmithstatic int
28151974Smsmithamrd_detach(device_t dev)
28251974Smsmith{
28351974Smsmith    struct amrd_softc *sc = (struct amrd_softc *)device_get_softc(dev);
28451974Smsmith
28565245Smsmith    debug_called(1);
28651974Smsmith
28765245Smsmith    if (sc->amrd_flags & AMRD_OPEN)
28865245Smsmith	return(EBUSY);
28965245Smsmith
29051974Smsmith    devstat_remove_entry(&sc->amrd_stats);
29165245Smsmith#ifdef FREEBSD_4
29265245Smsmith    if (--disks_registered == 0)
29365245Smsmith	cdevsw_remove(&amrddisk_cdevsw);
29465245Smsmith#else
295111216Sphk    disk_destroy(&sc->amrd_disk);
29665245Smsmith#endif
29751974Smsmith    return(0);
29851974Smsmith}
29951974Smsmith
300