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.
27119418Sobrien */
28139749Simp/*-
29106225Semoore * Copyright (c) 2002 Eric Moore
30106225Semoore * Copyright (c) 2002 LSI Logic Corporation
31106225Semoore * All rights reserved.
32106225Semoore *
33106225Semoore * Redistribution and use in source and binary forms, with or without
34106225Semoore * modification, are permitted provided that the following conditions
35106225Semoore * are met:
36106225Semoore * 1. Redistributions of source code must retain the above copyright
37106225Semoore *    notice, this list of conditions and the following disclaimer.
38106225Semoore * 2. Redistributions in binary form must reproduce the above copyright
39106225Semoore *    notice, this list of conditions and the following disclaimer in the
40106225Semoore *    documentation and/or other materials provided with the distribution.
41105419Semoore * 3. The party using or redistributing the source code and binary forms
42106225Semoore *    agrees to the disclaimer below and the terms and conditions set forth
43105419Semoore *    herein.
44105419Semoore *
45106225Semoore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
46106225Semoore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48106225Semoore * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
49106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55106225Semoore * SUCH DAMAGE.
5651974Smsmith */
5751974Smsmith
58119418Sobrien#include <sys/cdefs.h>
59119418Sobrien__FBSDID("$FreeBSD$");
60119418Sobrien
6151974Smsmith/*
6251974Smsmith * Disk driver for AMI MegaRaid controllers
6351974Smsmith */
6451974Smsmith
6551974Smsmith#include <sys/param.h>
6651974Smsmith#include <sys/systm.h>
6751974Smsmith#include <sys/kernel.h>
68129879Sphk#include <sys/module.h>
6951974Smsmith
70148850Sscottl#include <sys/bio.h>
7151974Smsmith#include <sys/bus.h>
7251974Smsmith#include <sys/conf.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
87111441Sphkstatic	disk_open_t	amrd_open;
88111441Sphkstatic	disk_strategy_t	amrd_strategy;
8951974Smsmith
9051974Smsmithstatic devclass_t	amrd_devclass;
9165245Smsmith#ifdef FREEBSD_4
92153409Sscottlint			amr_disks_registered = 0;
9365245Smsmith#endif
9451974Smsmith
9551974Smsmithstatic device_method_t amrd_methods[] = {
9651974Smsmith    DEVMETHOD(device_probe,	amrd_probe),
9751974Smsmith    DEVMETHOD(device_attach,	amrd_attach),
9851974Smsmith    DEVMETHOD(device_detach,	amrd_detach),
9951974Smsmith    { 0, 0 }
10051974Smsmith};
10151974Smsmith
10251974Smsmithstatic driver_t amrd_driver = {
10351974Smsmith    "amrd",
10451974Smsmith    amrd_methods,
10551974Smsmith    sizeof(struct amrd_softc)
10651974Smsmith};
10751974Smsmith
10851974SmsmithDRIVER_MODULE(amrd, amr, amrd_driver, amrd_devclass, 0, 0);
10951974Smsmith
11051974Smsmithstatic int
111111441Sphkamrd_open(struct disk *dp)
11251974Smsmith{
113111441Sphk    struct amrd_softc	*sc = (struct amrd_softc *)dp->d_drv1;
11451974Smsmith
11565245Smsmith    debug_called(1);
116105419Semoore
11751974Smsmith    if (sc == NULL)
11851974Smsmith	return (ENXIO);
11951974Smsmith
12051974Smsmith    /* controller not active? */
12151974Smsmith    if (sc->amrd_controller->amr_state & AMR_STATE_SHUTDOWN)
12251974Smsmith	return(ENXIO);
12351974Smsmith
12451974Smsmith    return (0);
12551974Smsmith}
126120988Sps/********************************************************************************
127120988Sps * System crashdump support
128120988Sps */
12951974Smsmith
130120988Spsstatic int
131120988Spsamrd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
132120988Sps{
133120988Sps
134120988Sps    struct amrd_softc	*amrd_sc;
135120988Sps    struct amr_softc	*amr_sc;
136120988Sps    int			error;
137120988Sps    struct disk		*dp;
138120988Sps
139120988Sps    dp = arg;
140120988Sps    amrd_sc = (struct amrd_softc *)dp->d_drv1;
141126116Scperciva    if (amrd_sc == NULL)
142126116Scperciva	return(ENXIO);
143120988Sps    amr_sc  = (struct amr_softc *)amrd_sc->amrd_controller;
144120988Sps
145120988Sps    if (length > 0) {
146120988Sps	int	driveno = amrd_sc->amrd_drive - amr_sc->amr_drive;
147120988Sps	if ((error = amr_dump_blocks(amr_sc,driveno,offset / AMR_BLKSIZE ,(void *)virtual,(int) length / AMR_BLKSIZE  )) != 0)
148120988Sps	    	return(error);
149120988Sps
150120988Sps    }
151120988Sps    return(0);
152120988Sps}
153120988Sps
15451974Smsmith/*
15551974Smsmith * Read/write routine for a buffer.  Finds the proper unit, range checks
15651974Smsmith * arguments, and schedules the transfer.  Does not wait for the transfer
15751974Smsmith * to complete.  Multi-page transfers are supported.  All I/O requests must
15851974Smsmith * be a multiple of a sector in length.
15951974Smsmith */
16051974Smsmithstatic void
16165245Smsmithamrd_strategy(struct bio *bio)
16251974Smsmith{
163111441Sphk    struct amrd_softc	*sc = (struct amrd_softc *)bio->bio_disk->d_drv1;
16451974Smsmith
16551974Smsmith    /* bogus disk? */
16651974Smsmith    if (sc == NULL) {
16765245Smsmith	bio->bio_error = EINVAL;
16851974Smsmith	goto bad;
16951974Smsmith    }
17051974Smsmith
17165245Smsmith    amr_submit_bio(sc->amrd_controller, bio);
17251974Smsmith    return;
17351974Smsmith
17451974Smsmith bad:
17565245Smsmith    bio->bio_flags |= BIO_ERROR;
17651974Smsmith
17751974Smsmith    /*
17851974Smsmith     * Correctly set the buf to indicate a completed transfer
17951974Smsmith     */
18065245Smsmith    bio->bio_resid = bio->bio_bcount;
18165245Smsmith    biodone(bio);
18251974Smsmith    return;
18351974Smsmith}
18451974Smsmith
18551974Smsmithvoid
18651974Smsmithamrd_intr(void *data)
18751974Smsmith{
18865245Smsmith    struct bio *bio = (struct bio *)data;
18951974Smsmith
19065245Smsmith    debug_called(2);
19158883Smsmith
19265245Smsmith    if (bio->bio_flags & BIO_ERROR) {
19365245Smsmith	bio->bio_error = EIO;
19465245Smsmith	debug(1, "i/o error\n");
19558883Smsmith    } else {
19665245Smsmith	bio->bio_resid = 0;
19758883Smsmith    }
19851974Smsmith
199148850Sscottl    biodone(bio);
20051974Smsmith}
20151974Smsmith
20251974Smsmithstatic int
20351974Smsmithamrd_probe(device_t dev)
20451974Smsmith{
20551974Smsmith
20665245Smsmith    debug_called(1);
207105419Semoore
208105419Semoore    device_set_desc(dev, "LSILogic MegaRAID logical drive");
20951974Smsmith    return (0);
21051974Smsmith}
21151974Smsmith
21251974Smsmithstatic int
21351974Smsmithamrd_attach(device_t dev)
21451974Smsmith{
21551974Smsmith    struct amrd_softc	*sc = (struct amrd_softc *)device_get_softc(dev);
21651974Smsmith    device_t		parent;
21751974Smsmith
21865245Smsmith    debug_called(1);
21951974Smsmith
22051974Smsmith    parent = device_get_parent(dev);
22151974Smsmith    sc->amrd_controller = (struct amr_softc *)device_get_softc(parent);
22251974Smsmith    sc->amrd_unit = device_get_unit(dev);
22351974Smsmith    sc->amrd_drive = device_get_ivars(dev);
22452274Smsmith    sc->amrd_dev = dev;
22551974Smsmith
22652784Smsmith    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
22751974Smsmith		  sc->amrd_drive->al_size / ((1024 * 1024) / AMR_BLKSIZE),
22865245Smsmith		  sc->amrd_drive->al_size, sc->amrd_drive->al_properties & AMR_DRV_RAID_MASK,
22965245Smsmith		  amr_describe_code(amr_table_drvstate, AMR_DRV_CURSTATE(sc->amrd_drive->al_state)));
23051974Smsmith
231125975Sphk    sc->amrd_disk = disk_alloc();
232125975Sphk    sc->amrd_disk->d_drv1 = sc;
233125975Sphk    sc->amrd_disk->d_maxsize = (AMR_NSEG - 1) * PAGE_SIZE;
234125975Sphk    sc->amrd_disk->d_open = amrd_open;
235125975Sphk    sc->amrd_disk->d_strategy = amrd_strategy;
236125975Sphk    sc->amrd_disk->d_name = "amrd";
237125975Sphk    sc->amrd_disk->d_dump = (dumper_t *)amrd_dump;
238125975Sphk    sc->amrd_disk->d_unit = sc->amrd_unit;
239163834Spjd    sc->amrd_disk->d_flags = DISKFLAG_CANFLUSHCACHE;
240148840Sscottl    sc->amrd_disk->d_sectorsize = AMR_BLKSIZE;
241148840Sscottl    sc->amrd_disk->d_mediasize = (off_t)sc->amrd_drive->al_size * AMR_BLKSIZE;
242148840Sscottl    sc->amrd_disk->d_fwsectors = sc->amrd_drive->al_sectors;
243148840Sscottl    sc->amrd_disk->d_fwheads = sc->amrd_drive->al_heads;
244125975Sphk    disk_create(sc->amrd_disk, DISK_VERSION);
24551974Smsmith
24651974Smsmith    return (0);
24751974Smsmith}
24851974Smsmith
24951974Smsmithstatic int
25051974Smsmithamrd_detach(device_t dev)
25151974Smsmith{
25251974Smsmith    struct amrd_softc *sc = (struct amrd_softc *)device_get_softc(dev);
25351974Smsmith
25465245Smsmith    debug_called(1);
25551974Smsmith
256125975Sphk    if (sc->amrd_disk->d_flags & DISKFLAG_OPEN)
25765245Smsmith	return(EBUSY);
25865245Smsmith
25965245Smsmith#ifdef FREEBSD_4
260153409Sscottl    if (--amr_disks_registered == 0)
26165245Smsmith	cdevsw_remove(&amrddisk_cdevsw);
26265245Smsmith#else
263125975Sphk    disk_destroy(sc->amrd_disk);
26465245Smsmith#endif
26551974Smsmith    return(0);
26651974Smsmith}
26751974Smsmith
268