mlx_disk.c revision 60074
1326941Sdim/*-
2326941Sdim * Copyright (c) 1999 Jonathan Lemon
3353358Sdim * Copyright (c) 1999 Michael Smith
4353358Sdim * All rights reserved.
5353358Sdim *
6326941Sdim * Redistribution and use in source and binary forms, with or without
7326941Sdim * modification, are permitted provided that the following conditions
8326941Sdim * are met:
9326941Sdim * 1. Redistributions of source code must retain the above copyright
10326941Sdim *    notice, this list of conditions and the following disclaimer.
11326941Sdim * 2. Redistributions in binary form must reproduce the above copyright
12326941Sdim *    notice, this list of conditions and the following disclaimer in the
13326941Sdim *    documentation and/or other materials provided with the distribution.
14326941Sdim *
15326941Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16326941Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17326941Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18326941Sdim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19326941Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20326941Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21326941Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22326941Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23326941Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24326941Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25326941Sdim * SUCH DAMAGE.
26326941Sdim *
27326941Sdim * $FreeBSD: head/sys/dev/mlx/mlx_disk.c 60074 2000-05-06 08:54:33Z msmith $
28326941Sdim */
29326941Sdim
30326941Sdim/*
31326941Sdim * Disk driver for Mylex DAC960 RAID adapters.
32326941Sdim */
33326941Sdim
34326941Sdim#include <sys/param.h>
35326941Sdim#include <sys/systm.h>
36326941Sdim#include <sys/kernel.h>
37326941Sdim
38360784Sdim#include <sys/bio.h>
39360784Sdim#include <sys/bus.h>
40326941Sdim#include <sys/conf.h>
41326941Sdim#include <sys/devicestat.h>
42326941Sdim#include <sys/disk.h>
43326941Sdim
44326941Sdim#include <machine/bus.h>
45326941Sdim#include <machine/clock.h>
46326941Sdim#include <sys/rman.h>
47326941Sdim
48326941Sdim#include <dev/mlx/mlxio.h>
49326941Sdim#include <dev/mlx/mlxvar.h>
50326941Sdim#include <dev/mlx/mlxreg.h>
51326941Sdim
52326941Sdim/* prototypes */
53326941Sdimstatic int mlxd_probe(device_t dev);
54326941Sdimstatic int mlxd_attach(device_t dev);
55326941Sdimstatic int mlxd_detach(device_t dev);
56326941Sdim
57326941Sdimstatic	d_open_t	mlxd_open;
58326941Sdimstatic	d_close_t	mlxd_close;
59326941Sdimstatic	d_strategy_t	mlxd_strategy;
60326941Sdimstatic	d_ioctl_t	mlxd_ioctl;
61326941Sdim
62326941Sdim#define MLXD_BDEV_MAJOR	27
63326941Sdim#define MLXD_CDEV_MAJOR	131
64326941Sdim
65326941Sdimstatic struct cdevsw mlxd_cdevsw = {
66326941Sdim		/* open */	mlxd_open,
67326941Sdim		/* close */	mlxd_close,
68326941Sdim		/* read */	physread,
69326941Sdim		/* write */	physwrite,
70326941Sdim		/* ioctl */	mlxd_ioctl,
71326941Sdim		/* poll */	nopoll,
72326941Sdim		/* mmap */	nommap,
73326941Sdim		/* strategy */	mlxd_strategy,
74326941Sdim		/* name */ 	"mlxd",
75326941Sdim		/* maj */	MLXD_CDEV_MAJOR,
76326941Sdim		/* dump */	nodump,
77326941Sdim		/* psize */ 	nopsize,
78326941Sdim		/* flags */	D_DISK,
79326941Sdim		/* bmaj */	MLXD_BDEV_MAJOR
80326941Sdim};
81326941Sdim
82326941Sdimdevclass_t		mlxd_devclass;
83326941Sdimstatic struct cdevsw	mlxddisk_cdevsw;
84326941Sdim
85326941Sdimstatic device_method_t mlxd_methods[] = {
86326941Sdim    DEVMETHOD(device_probe,	mlxd_probe),
87326941Sdim    DEVMETHOD(device_attach,	mlxd_attach),
88326941Sdim    DEVMETHOD(device_detach,	mlxd_detach),
89326941Sdim    { 0, 0 }
90326941Sdim};
91326941Sdim
92326941Sdimstatic driver_t mlxd_driver = {
93326941Sdim    "mlxd",
94326941Sdim    mlxd_methods,
95326941Sdim    sizeof(struct mlxd_softc)
96326941Sdim};
97326941Sdim
98326941SdimDRIVER_MODULE(mlxd, mlx, mlxd_driver, mlxd_devclass, 0, 0);
99326941Sdim
100326941Sdimstatic int
101326941Sdimmlxd_open(dev_t dev, int flags, int fmt, struct proc *p)
102326941Sdim{
103326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
104326941Sdim    struct disklabel	*label;
105326941Sdim
106326941Sdim    debug_called(1);
107326941Sdim
108326941Sdim    if (sc == NULL)
109326941Sdim	return (ENXIO);
110326941Sdim
111326941Sdim    /* controller not active? */
112326941Sdim    if (sc->mlxd_controller->mlx_state & MLX_STATE_SHUTDOWN)
113326941Sdim	return(ENXIO);
114326941Sdim
115326941Sdim    label = &sc->mlxd_disk.d_label;
116326941Sdim    bzero(label, sizeof(*label));
117326941Sdim    label->d_type = DTYPE_SCSI;
118326941Sdim    label->d_secsize    = MLX_BLKSIZE;
119326941Sdim    label->d_nsectors   = sc->mlxd_drive->ms_sectors;
120326941Sdim    label->d_ntracks    = sc->mlxd_drive->ms_heads;
121326941Sdim    label->d_ncylinders = sc->mlxd_drive->ms_cylinders;
122326941Sdim    label->d_secpercyl  = sc->mlxd_drive->ms_sectors * sc->mlxd_drive->ms_heads;
123326941Sdim    label->d_secperunit = sc->mlxd_drive->ms_size;
124326941Sdim
125326941Sdim    sc->mlxd_flags |= MLXD_OPEN;
126326941Sdim    return (0);
127326941Sdim}
128326941Sdim
129326941Sdimstatic int
130326941Sdimmlxd_close(dev_t dev, int flags, int fmt, struct proc *p)
131326941Sdim{
132326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
133326941Sdim
134326941Sdim    debug_called(1);
135326941Sdim
136326941Sdim    if (sc == NULL)
137326941Sdim	return (ENXIO);
138326941Sdim    sc->mlxd_flags &= ~MLXD_OPEN;
139326941Sdim    return (0);
140326941Sdim}
141326941Sdim
142326941Sdimstatic int
143326941Sdimmlxd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
144326941Sdim{
145326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)dev->si_drv1;
146326941Sdim    int error;
147326941Sdim
148326941Sdim    debug_called(1);
149326941Sdim
150326941Sdim    if (sc == NULL)
151326941Sdim	return (ENXIO);
152326941Sdim
153326941Sdim    if ((error = mlx_submit_ioctl(sc->mlxd_controller, sc->mlxd_drive, cmd, addr, flag, p)) != ENOIOCTL) {
154326941Sdim	debug(0, "mlx_submit_ioctl returned %d\n", error);
155326941Sdim	return(error);
156326941Sdim    }
157326941Sdim    return (ENOTTY);
158326941Sdim}
159326941Sdim
160326941Sdim/*
161326941Sdim * Read/write routine for a buffer.  Finds the proper unit, range checks
162326941Sdim * arguments, and schedules the transfer.  Does not wait for the transfer
163326941Sdim * to complete.  Multi-page transfers are supported.  All I/O requests must
164326941Sdim * be a multiple of a sector in length.
165326941Sdim */
166326941Sdimstatic void
167326941Sdimmlxd_strategy(struct bio *bp)
168326941Sdim{
169326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->bio_dev->si_drv1;
170326941Sdim
171326941Sdim    debug_called(1);
172326941Sdim
173326941Sdim    /* bogus disk? */
174326941Sdim    if (sc == NULL) {
175326941Sdim	bp->bio_error = EINVAL;
176326941Sdim	goto bad;
177326941Sdim    }
178326941Sdim
179326941Sdim    /* XXX may only be temporarily offline - sleep? */
180326941Sdim    if (sc->mlxd_drive->ms_state == MLX_SYSD_OFFLINE) {
181326941Sdim	bp->bio_error = ENXIO;
182326941Sdim	goto bad;
183326941Sdim    }
184326941Sdim
185326941Sdim    /* do-nothing operation */
186326941Sdim    if (bp->bio_bcount == 0)
187326941Sdim	goto done;
188326941Sdim
189326941Sdim    devstat_start_transaction(&sc->mlxd_stats);
190326941Sdim    mlx_submit_buf(sc->mlxd_controller, bp);
191326941Sdim    return;
192326941Sdim
193326941Sdim bad:
194326941Sdim    bp->bio_flags |= BIO_ERROR;
195326941Sdim
196326941Sdim done:
197326941Sdim    /*
198326941Sdim     * Correctly set the buf to indicate a completed transfer
199326941Sdim     */
200326941Sdim    bp->bio_resid = bp->bio_bcount;
201326941Sdim    biodone(bp);
202326941Sdim    return;
203326941Sdim}
204326941Sdim
205326941Sdimvoid
206326941Sdimmlxd_intr(void *data)
207326941Sdim{
208326941Sdim    struct bio *bp = (struct bio *)data;
209326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)bp->bio_dev->si_drv1;
210326941Sdim
211326941Sdim    debug_called(1);
212326941Sdim
213326941Sdim    if (bp->bio_flags & BIO_ERROR)
214326941Sdim	bp->bio_error = EIO;
215326941Sdim    else
216326941Sdim	bp->bio_resid = 0;
217326941Sdim
218326941Sdim    devstat_end_transaction_bio(&sc->mlxd_stats, bp);
219326941Sdim    biodone(bp);
220326941Sdim}
221326941Sdim
222326941Sdimstatic int
223326941Sdimmlxd_probe(device_t dev)
224326941Sdim{
225326941Sdim
226326941Sdim    debug_called(1);
227326941Sdim
228326941Sdim    device_set_desc(dev, "Mylex System Drive");
229326941Sdim    return (0);
230326941Sdim}
231326941Sdim
232326941Sdimstatic int
233326941Sdimmlxd_attach(device_t dev)
234326941Sdim{
235326941Sdim    struct mlxd_softc	*sc = (struct mlxd_softc *)device_get_softc(dev);
236326941Sdim    device_t		parent;
237326941Sdim    char		*state;
238326941Sdim    dev_t		dsk;
239326941Sdim    int			s1, s2;
240353358Sdim
241353358Sdim    debug_called(1);
242326941Sdim
243326941Sdim    parent = device_get_parent(dev);
244326941Sdim    sc->mlxd_controller = (struct mlx_softc *)device_get_softc(parent);
245326941Sdim    sc->mlxd_unit = device_get_unit(dev);
246326941Sdim    sc->mlxd_drive = device_get_ivars(dev);
247326941Sdim    sc->mlxd_dev = dev;
248326941Sdim
249326941Sdim    switch(sc->mlxd_drive->ms_state) {
250326941Sdim    case MLX_SYSD_ONLINE:
251326941Sdim	state = "online";
252326941Sdim	break;
253326941Sdim    case MLX_SYSD_CRITICAL:
254326941Sdim	state = "critical";
255326941Sdim	break;
256326941Sdim    case MLX_SYSD_OFFLINE:
257326941Sdim	state = "offline";
258326941Sdim	break;
259326941Sdim    default:
260326941Sdim	state = "unknown state";
261326941Sdim    }
262326941Sdim
263326941Sdim    device_printf(dev, "%uMB (%u sectors) RAID %d (%s)\n",
264326941Sdim		  sc->mlxd_drive->ms_size / ((1024 * 1024) / MLX_BLKSIZE),
265326941Sdim		  sc->mlxd_drive->ms_size, sc->mlxd_drive->ms_raidlevel, state);
266326941Sdim
267326941Sdim    devstat_add_entry(&sc->mlxd_stats, "mlxd", sc->mlxd_unit, MLX_BLKSIZE,
268326941Sdim		      DEVSTAT_NO_ORDERED_TAGS,
269326941Sdim		      DEVSTAT_TYPE_STORARRAY | DEVSTAT_TYPE_IF_OTHER,
270326941Sdim		      DEVSTAT_PRIORITY_ARRAY);
271326941Sdim
272326941Sdim    dsk = disk_create(sc->mlxd_unit, &sc->mlxd_disk, 0, &mlxd_cdevsw, &mlxddisk_cdevsw);
273326941Sdim    dsk->si_drv1 = sc;
274326941Sdim    sc->mlxd_dev_t = dsk;
275326941Sdim
276326941Sdim    /*
277326941Sdim     * Set maximum I/O size to the lesser of the recommended maximum and the practical
278326941Sdim     * maximum.
279326941Sdim     */
280326941Sdim    s1 = sc->mlxd_controller->mlx_enq2->me_maxblk * MLX_BLKSIZE;
281326941Sdim    s2 = (sc->mlxd_controller->mlx_enq2->me_max_sg - 1) * PAGE_SIZE;
282326941Sdim    dsk->si_iosize_max = imin(s1, s2);
283326941Sdim
284326941Sdim    return (0);
285326941Sdim}
286326941Sdim
287326941Sdimstatic int
288326941Sdimmlxd_detach(device_t dev)
289326941Sdim{
290326941Sdim    struct mlxd_softc *sc = (struct mlxd_softc *)device_get_softc(dev);
291326941Sdim
292326941Sdim    debug_called(1);
293326941Sdim
294326941Sdim    devstat_remove_entry(&sc->mlxd_stats);
295326941Sdim    disk_destroy(sc->mlxd_dev_t);
296326941Sdim
297326941Sdim    return(0);
298326941Sdim}
299326941Sdim
300326941Sdim