aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/amr/amrvar.h
blob: 6a136be0645fcfd0bb5464ff0fbd57f6b5ac7ed7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*-
 * Copyright (c) 1999 Michael Smith
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      $FreeBSD$
 */

/*
 * We could actually use all 17 segments, but using only 16 means that
 * each scatter/gather map is 128 bytes in size, and thus we don't have to worry about
 * maps crossing page boundaries.
 */
#define AMR_NSEG	16

#define AMR_CFG_BASE	0x10
#define AMR_CFG_SIG	0xa0
#define AMR_SIGNATURE	0x3344

#define AMR_MAXCMD	255		/* ident = 0 not allowed */
#define AMR_LIMITCMD	120		/* maximum count of outstanding commands */
#define AMR_MAXLD      	40

#define AMR_BLKSIZE	512

struct amr_softc;

/*
 * Per-logical-drive datastructure
 */
struct amr_logdrive
{
    u_int32_t	al_size;
    int		al_state;
    int		al_properties;
    
    /* synthetic geometry */
    int		al_cylinders;
    int		al_heads;
    int		al_sectors;
    
    /* driver */
    device_t	al_disk;
};


/*
 * Per-command control structure.
 */
struct amr_command
{
    TAILQ_ENTRY(struct amr_command)	ac_link;

    struct amr_softc		*ac_sc;
    u_int8_t			ac_slot;
    int				ac_status;
#define AMR_STATUS_BUSY		0xffff
#define AMR_STATUS_WEDGED	0xdead
#define AMR_STATUS_LATE		0xdeed
    struct amr_mailbox		ac_mailbox;
    u_int32_t			ac_sgphys;
    int				ac_nsgent;
    int				ac_flags;
#define AMR_CMD_DATAIN		(1<<0)
#define AMR_CMD_DATAOUT		(1<<1)
#define AMR_CMD_PRIORITY	(1<<2)
    time_t			ac_stamp;

    void			*ac_data;
    size_t			ac_length;
    bus_dmamap_t		ac_dmamap;
    u_int32_t			ac_dataphys;

    void			(* ac_complete)(struct amr_command *ac);
    void			*ac_private;
};

struct amr_softc 
{
    /* bus attachments */
    device_t			amr_dev;
    struct resource		*amr_reg;		/* control registers */
    bus_space_handle_t		amr_bhandle;
    bus_space_tag_t		amr_btag;
    bus_dma_tag_t		amr_parent_dmat;	/* parent DMA tag */
    bus_dma_tag_t		amr_buffer_dmat;	/* data buffer DMA tag */
    struct resource		*amr_irq;		/* interrupt */
    void			*amr_intr;

    /* mailbox */
    volatile struct amr_mailbox		*amr_mailbox;
    volatile struct amr_mailbox64	*amr_mailbox64;
    u_int32_t			amr_mailboxphys;
    bus_dma_tag_t		amr_mailbox_dmat;
    bus_dmamap_t		amr_mailbox_dmamap;

    /* scatter/gather lists and their controller-visible mappings */
    struct amr_sgentry		*amr_sgtable;		/* s/g lists */
    u_int32_t			amr_sgbusaddr;		/* s/g table base address in bus space */
    bus_dma_tag_t		amr_sg_dmat;		/* s/g buffer DMA tag */
    bus_dmamap_t		amr_sg_dmamap;		/* map for s/g buffers */

    /* controller limits and features */
    int				amr_maxio;		/* maximum number of I/O transactions */
    int				amr_maxdrives;		/* max number of logical drives */
    
    /* connected logical drives */
    struct amr_logdrive		amr_drive[AMR_MAXLD];

    /* controller status */
    int				amr_state;
#define AMR_STATE_OPEN		(1<<0)
#define AMR_STATE_SUSPEND	(1<<1)
#define AMR_STATE_INTEN		(1<<2)
#define AMR_STATE_SHUTDOWN	(1<<3)
    struct callout_handle	amr_timeout;		/* periodic status check */

    /* per-controller queues */
    struct bio_queue_head 	amr_bioq;		/* pending I/O */
    int				amr_waitbufs;
    struct amr_command		*amr_busycmd[AMR_MAXCMD];
    int				amr_busycmdcount;
    TAILQ_HEAD(, struct amr_command)	amr_work;
    int				amr_workcount;
    TAILQ_HEAD(, struct amr_command)	amr_freecmds;

    int				amr_locks;		/* reentrancy avoidance */

    /* controller type-specific support */
    int				amr_type;
#define AMR_TYPE_STD		0
#define AMR_TYPE_QUARTZ		1
    void			(* amr_submit_command)(struct amr_softc *sc);
    int				(* amr_get_work)(struct amr_softc *sc, struct amr_mailbox *mbsave);
    void			(* amr_attach_mailbox)(struct amr_softc *sc);
};

/*
 * Simple (stupid) locks.
 *
 * Note that these are designed to avoid reentrancy, not concurrency, and will
 * need to be replaced with something better.
 */
#define AMR_LOCK_COMPLETING     (1<<0)
#define AMR_LOCK_STARTING       (1<<1)

static __inline int
amr_lock_tas(struct amr_softc *sc, int lock)
{
    if ((sc)->amr_locks & (lock))
        return(1);
    atomic_set_int(&sc->amr_locks, lock);
    return(0);
}

static __inline void
amr_lock_clr(struct amr_softc *sc, int lock)
{
    atomic_clear_int(&sc->amr_locks, lock);
}

/*
 * I/O primitives
 */
/* Quartz */
#define AMR_QPUT_IDB(sc, val)	bus_space_write_4(sc->amr_btag, sc->amr_bhandle, AMR_QIDB, val)
#define AMR_QGET_IDB(sc)	bus_space_read_4 (sc->amr_btag, sc->amr_bhandle, AMR_QIDB)
#define AMR_QPUT_ODB(sc, val)	bus_space_write_4(sc->amr_btag, sc->amr_bhandle, AMR_QODB, val)
#define AMR_QGET_ODB(sc)	bus_space_read_4 (sc->amr_btag, sc->amr_bhandle, AMR_QODB)

/* Standard */
#define AMR_SPUT_ISTAT(sc, val)	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, AMR_SINTR, val)
#define AMR_SGET_ISTAT(sc)	bus_space_read_1 (sc->amr_btag, sc->amr_bhandle, AMR_SINTR)
#define AMR_SACK_INTERRUPT(sc)	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, AMR_SCMD, AMR_SCMD_ACKINTR)
#define AMR_SPOST_COMMAND(sc)	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, AMR_SCMD, AMR_SCMD_POST)
#define AMR_SGET_MBSTAT(sc)	bus_space_read_1 (sc->amr_btag, sc->amr_bhandle, AMR_SMBOX_BUSY)
#define AMR_SENABLE_INTR(sc)											\
	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, AMR_STOGGLE, 						\
			  bus_space_read_1(sc->amr_btag, sc->amr_bhandle, AMR_STOGGLE) | AMR_STOGL_IENABLE)
#define AMR_SDISABLE_INTR(sc)											\
	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, AMR_STOGGLE, 						\
			  bus_space_read_1(sc->amr_btag, sc->amr_bhandle, AMR_STOGGLE) & ~AMR_STOGL_IENABLE)
#define AMR_SBYTE_SET(sc, reg, val)	bus_space_write_1(sc->amr_btag, sc->amr_bhandle, reg, val)

/*
 * Interface between bus connections and driver core.
 */
extern void             amr_free(struct amr_softc *sc);
extern int              amr_attach(struct amr_softc *sc);
extern void             amr_startup(struct amr_softc *sc);
extern void             amr_intr(void *data);
extern int              amr_detach(device_t dev);
extern int              amr_shutdown(device_t dev);
extern int              amr_suspend(device_t dev);
extern int              amr_resume(device_t dev);
extern d_open_t         amr_open;
extern d_close_t        amr_close;
extern d_ioctl_t        amr_ioctl;

extern devclass_t       amr_devclass;

/*
 * MegaRAID logical disk driver
 */
struct amrd_softc 
{
    device_t		amrd_dev;
    dev_t		amrd_dev_t;
    struct amr_softc	*amrd_controller;
    struct amr_logdrive	*amrd_drive;
    struct disk		amrd_disk;
    struct devstat	amrd_stats;
    struct disklabel	amrd_label;
    int			amrd_unit;
    int			amrd_flags;
#define AMRD_OPEN	(1<<0)		/* drive is open (can't shut down) */
};

/*
 * Interface between driver core and disk driver (should be using a bus?)
 */
extern int	amr_submit_buf(struct amr_softc *sc, struct bio *bp);
extern int	amr_submit_ioctl(struct amr_softc *sc, struct amr_logdrive *drive, u_long cmd, 
				 caddr_t addr, int32_t flag, struct proc *p);
extern void	amrd_intr(void *data);

extern void	amr_report(void);