| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 2000 Michael Smith | |
| 3 | * Copyright (c) 2001 Scott Long | |
| 4 | * Copyright (c) 2000 BSDi | |
| 5 | * Copyright (c) 2001 Adaptec, Inc. | |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in the | |
| 15 | * documentation and/or other materials provided with the distribution. | |
| 16 | * | |
| 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
| 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 27 | * SUCH DAMAGE. | |
| 28 | * | |
| e9ae7f4f | 29 | * $FreeBSD: src/sys/dev/aac/aac.c,v 1.165 2010/09/29 14:22:00 emaste Exp $ |
| 984263bc MD |
30 | */ |
| 31 | ||
| 32 | /* | |
| 33 | * Driver for the Adaptec 'FSA' family of PCI/SCSI RAID adapters. | |
| 34 | */ | |
| d9773475 | 35 | #define AAC_DRIVERNAME "aac" |
| 984263bc MD |
36 | |
| 37 | #include "opt_aac.h" | |
| 38 | ||
| 39 | /* #include <stddef.h> */ | |
| 40 | #include <sys/param.h> | |
| 41 | #include <sys/systm.h> | |
| 42 | #include <sys/malloc.h> | |
| 43 | #include <sys/kernel.h> | |
| 44 | #include <sys/kthread.h> | |
| 45 | #include <sys/sysctl.h> | |
| e9ae7f4f | 46 | #include <sys/poll.h> |
| 984263bc MD |
47 | |
| 48 | #include <sys/bus.h> | |
| 49 | #include <sys/conf.h> | |
| 984263bc MD |
50 | #include <sys/signalvar.h> |
| 51 | #include <sys/time.h> | |
| 52 | #include <sys/eventhandler.h> | |
| d9773475 PA |
53 | #include <sys/rman.h> |
| 54 | ||
| e9ae7f4f SW |
55 | #include <sys/bus_dma.h> |
| 56 | #include <sys/device.h> | |
| 684a93c4 MD |
57 | #include <sys/mplock2.h> |
| 58 | ||
| d9773475 PA |
59 | #include <bus/pci/pcireg.h> |
| 60 | #include <bus/pci/pcivar.h> | |
| 984263bc | 61 | |
| e9ae7f4f SW |
62 | #include <dev/raid/aac/aacreg.h> |
| 63 | #include <dev/raid/aac/aac_ioctl.h> | |
| 64 | #include <dev/raid/aac/aacvar.h> | |
| 65 | #include <dev/raid/aac/aac_tables.h> | |
| 984263bc MD |
66 | |
| 67 | static void aac_startup(void *arg); | |
| 68 | static void aac_add_container(struct aac_softc *sc, | |
| 69 | struct aac_mntinforesp *mir, int f); | |
| 70 | static void aac_get_bus_info(struct aac_softc *sc); | |
| e9ae7f4f | 71 | static void aac_daemon(void *arg); |
| 984263bc MD |
72 | |
| 73 | /* Command Processing */ | |
| e9ae7f4f | 74 | static void aac_timeout(struct aac_softc *sc); |
| 984263bc MD |
75 | static void aac_complete(void *context, int pending); |
| 76 | static int aac_bio_command(struct aac_softc *sc, struct aac_command **cmp); | |
| 77 | static void aac_bio_complete(struct aac_command *cm); | |
| d9773475 | 78 | static int aac_wait_command(struct aac_command *cm); |
| cd8ab232 | 79 | static void aac_command_thread(void *arg); |
| 984263bc MD |
80 | |
| 81 | /* Command Buffer Management */ | |
| d9773475 PA |
82 | static void aac_map_command_sg(void *arg, bus_dma_segment_t *segs, |
| 83 | int nseg, int error); | |
| 984263bc MD |
84 | static void aac_map_command_helper(void *arg, bus_dma_segment_t *segs, |
| 85 | int nseg, int error); | |
| 86 | static int aac_alloc_commands(struct aac_softc *sc); | |
| 87 | static void aac_free_commands(struct aac_softc *sc); | |
| 984263bc MD |
88 | static void aac_unmap_command(struct aac_command *cm); |
| 89 | ||
| 90 | /* Hardware Interface */ | |
| e9ae7f4f | 91 | static int aac_alloc(struct aac_softc *sc); |
| 984263bc MD |
92 | static void aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, |
| 93 | int error); | |
| 94 | static int aac_check_firmware(struct aac_softc *sc); | |
| 95 | static int aac_init(struct aac_softc *sc); | |
| 96 | static int aac_sync_command(struct aac_softc *sc, u_int32_t command, | |
| 97 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, | |
| 98 | u_int32_t arg3, u_int32_t *sp); | |
| e9ae7f4f | 99 | static int aac_setup_intr(struct aac_softc *sc); |
| 984263bc MD |
100 | static int aac_enqueue_fib(struct aac_softc *sc, int queue, |
| 101 | struct aac_command *cm); | |
| 102 | static int aac_dequeue_fib(struct aac_softc *sc, int queue, | |
| 103 | u_int32_t *fib_size, struct aac_fib **fib_addr); | |
| 104 | static int aac_enqueue_response(struct aac_softc *sc, int queue, | |
| 105 | struct aac_fib *fib); | |
| 106 | ||
| 984263bc MD |
107 | /* StrongARM interface */ |
| 108 | static int aac_sa_get_fwstatus(struct aac_softc *sc); | |
| 109 | static void aac_sa_qnotify(struct aac_softc *sc, int qbit); | |
| 110 | static int aac_sa_get_istatus(struct aac_softc *sc); | |
| 111 | static void aac_sa_clear_istatus(struct aac_softc *sc, int mask); | |
| 112 | static void aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, | |
| 113 | u_int32_t arg0, u_int32_t arg1, | |
| 114 | u_int32_t arg2, u_int32_t arg3); | |
| 115 | static int aac_sa_get_mailbox(struct aac_softc *sc, int mb); | |
| 116 | static void aac_sa_set_interrupts(struct aac_softc *sc, int enable); | |
| 117 | ||
| 118 | struct aac_interface aac_sa_interface = { | |
| 119 | aac_sa_get_fwstatus, | |
| 120 | aac_sa_qnotify, | |
| 121 | aac_sa_get_istatus, | |
| 122 | aac_sa_clear_istatus, | |
| 123 | aac_sa_set_mailbox, | |
| 124 | aac_sa_get_mailbox, | |
| d9773475 PA |
125 | aac_sa_set_interrupts, |
| 126 | NULL, NULL, NULL | |
| 984263bc MD |
127 | }; |
| 128 | ||
| d9773475 | 129 | /* i960Rx interface */ |
| 984263bc MD |
130 | static int aac_rx_get_fwstatus(struct aac_softc *sc); |
| 131 | static void aac_rx_qnotify(struct aac_softc *sc, int qbit); | |
| 132 | static int aac_rx_get_istatus(struct aac_softc *sc); | |
| 133 | static void aac_rx_clear_istatus(struct aac_softc *sc, int mask); | |
| 134 | static void aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, | |
| 135 | u_int32_t arg0, u_int32_t arg1, | |
| 136 | u_int32_t arg2, u_int32_t arg3); | |
| 137 | static int aac_rx_get_mailbox(struct aac_softc *sc, int mb); | |
| 138 | static void aac_rx_set_interrupts(struct aac_softc *sc, int enable); | |
| d9773475 PA |
139 | static int aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm); |
| 140 | static int aac_rx_get_outb_queue(struct aac_softc *sc); | |
| 141 | static void aac_rx_set_outb_queue(struct aac_softc *sc, int index); | |
| 984263bc MD |
142 | |
| 143 | struct aac_interface aac_rx_interface = { | |
| 144 | aac_rx_get_fwstatus, | |
| 145 | aac_rx_qnotify, | |
| 146 | aac_rx_get_istatus, | |
| 147 | aac_rx_clear_istatus, | |
| 148 | aac_rx_set_mailbox, | |
| 149 | aac_rx_get_mailbox, | |
| d9773475 PA |
150 | aac_rx_set_interrupts, |
| 151 | aac_rx_send_command, | |
| 152 | aac_rx_get_outb_queue, | |
| 153 | aac_rx_set_outb_queue | |
| 154 | }; | |
| 155 | ||
| 156 | /* Rocket/MIPS interface */ | |
| 157 | static int aac_rkt_get_fwstatus(struct aac_softc *sc); | |
| 158 | static void aac_rkt_qnotify(struct aac_softc *sc, int qbit); | |
| 159 | static int aac_rkt_get_istatus(struct aac_softc *sc); | |
| 160 | static void aac_rkt_clear_istatus(struct aac_softc *sc, int mask); | |
| 161 | static void aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, | |
| 162 | u_int32_t arg0, u_int32_t arg1, | |
| 163 | u_int32_t arg2, u_int32_t arg3); | |
| 164 | static int aac_rkt_get_mailbox(struct aac_softc *sc, int mb); | |
| 165 | static void aac_rkt_set_interrupts(struct aac_softc *sc, int enable); | |
| 166 | static int aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm); | |
| 167 | static int aac_rkt_get_outb_queue(struct aac_softc *sc); | |
| 168 | static void aac_rkt_set_outb_queue(struct aac_softc *sc, int index); | |
| 169 | ||
| 170 | struct aac_interface aac_rkt_interface = { | |
| 171 | aac_rkt_get_fwstatus, | |
| 172 | aac_rkt_qnotify, | |
| 173 | aac_rkt_get_istatus, | |
| 174 | aac_rkt_clear_istatus, | |
| 175 | aac_rkt_set_mailbox, | |
| 176 | aac_rkt_get_mailbox, | |
| 177 | aac_rkt_set_interrupts, | |
| 178 | aac_rkt_send_command, | |
| 179 | aac_rkt_get_outb_queue, | |
| 180 | aac_rkt_set_outb_queue | |
| 984263bc MD |
181 | }; |
| 182 | ||
| 183 | /* Debugging and Diagnostics */ | |
| 184 | static void aac_describe_controller(struct aac_softc *sc); | |
| 185 | static char *aac_describe_code(struct aac_code_lookup *table, | |
| 186 | u_int32_t code); | |
| 187 | ||
| 188 | /* Management Interface */ | |
| 189 | static d_open_t aac_open; | |
| 190 | static d_close_t aac_close; | |
| 191 | static d_ioctl_t aac_ioctl; | |
| eda1a08c SG |
192 | static d_kqfilter_t aac_kqfilter; |
| 193 | static void aac_filter_detach(struct knote *kn); | |
| e9ae7f4f SW |
194 | static int aac_filter_read(struct knote *kn, long hint); |
| 195 | static int aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib); | |
| 196 | static int aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg); | |
| 984263bc MD |
197 | static void aac_handle_aif(struct aac_softc *sc, |
| 198 | struct aac_fib *fib); | |
| 199 | static int aac_rev_check(struct aac_softc *sc, caddr_t udata); | |
| e9ae7f4f SW |
200 | static int aac_open_aif(struct aac_softc *sc, caddr_t arg); |
| 201 | static int aac_close_aif(struct aac_softc *sc, caddr_t arg); | |
| 984263bc | 202 | static int aac_getnext_aif(struct aac_softc *sc, caddr_t arg); |
| e9ae7f4f SW |
203 | static int aac_return_aif(struct aac_softc *sc, |
| 204 | struct aac_fib_context *ctx, caddr_t uptr); | |
| 984263bc | 205 | static int aac_query_disk(struct aac_softc *sc, caddr_t uptr); |
| d9773475 | 206 | static int aac_get_pci_info(struct aac_softc *sc, caddr_t uptr); |
| e9ae7f4f | 207 | static int aac_supported_features(struct aac_softc *sc, caddr_t uptr); |
| d9773475 | 208 | static void aac_ioctl_event(struct aac_softc *sc, |
| e9ae7f4f SW |
209 | struct aac_event *event, void *arg); |
| 210 | static struct aac_mntinforesp * | |
| 211 | aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid); | |
| 212 | ||
| fef8985e | 213 | static struct dev_ops aac_ops = { |
| 88abd8b5 | 214 | { "aac", 0, 0 }, |
| fef8985e MD |
215 | .d_open = aac_open, |
| 216 | .d_close = aac_close, | |
| 217 | .d_ioctl = aac_ioctl, | |
| eda1a08c | 218 | .d_kqfilter = aac_kqfilter |
| 984263bc MD |
219 | }; |
| 220 | ||
| 221 | MALLOC_DEFINE(M_AACBUF, "aacbuf", "Buffers for the AAC driver"); | |
| 222 | ||
| 223 | /* sysctl node */ | |
| 224 | SYSCTL_NODE(_hw, OID_AUTO, aac, CTLFLAG_RD, 0, "AAC driver parameters"); | |
| 225 | ||
| 226 | /* | |
| 227 | * Device Interface | |
| 228 | */ | |
| 229 | ||
| 230 | /* | |
| e9ae7f4f | 231 | * Initialize the controller and softc |
| 984263bc MD |
232 | */ |
| 233 | int | |
| 234 | aac_attach(struct aac_softc *sc) | |
| 235 | { | |
| 236 | int error, unit; | |
| 237 | ||
| e9ae7f4f | 238 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
239 | |
| 240 | /* | |
| e9ae7f4f | 241 | * Initialize per-controller queues. |
| 984263bc MD |
242 | */ |
| 243 | aac_initq_free(sc); | |
| 244 | aac_initq_ready(sc); | |
| 245 | aac_initq_busy(sc); | |
| 984263bc MD |
246 | aac_initq_bio(sc); |
| 247 | ||
| 984263bc | 248 | /* |
| e9ae7f4f | 249 | * Initialize command-completion task. |
| 984263bc MD |
250 | */ |
| 251 | TASK_INIT(&sc->aac_task_complete, 0, aac_complete, sc); | |
| 984263bc MD |
252 | |
| 253 | /* mark controller as suspended until we get ourselves organised */ | |
| 254 | sc->aac_state |= AAC_STATE_SUSPEND; | |
| 255 | ||
| 256 | /* | |
| 257 | * Check that the firmware on the card is supported. | |
| 258 | */ | |
| 259 | if ((error = aac_check_firmware(sc)) != 0) | |
| 260 | return(error); | |
| 261 | ||
| d9773475 PA |
262 | /* |
| 263 | * Initialize locks | |
| 264 | */ | |
| e9ae7f4f SW |
265 | lockinit(&sc->aac_aifq_lock, "AAC AIF lock", 0, LK_CANRECURSE); |
| 266 | lockinit(&sc->aac_io_lock, "AAC I/O lock", 0, LK_CANRECURSE); | |
| 267 | lockinit(&sc->aac_container_lock, "AAC container lock", 0, LK_CANRECURSE); | |
| d9773475 PA |
268 | TAILQ_INIT(&sc->aac_container_tqh); |
| 269 | TAILQ_INIT(&sc->aac_ev_cmfree); | |
| 270 | ||
| e9ae7f4f SW |
271 | /* Initialize the clock daemon callout. */ |
| 272 | callout_init(&sc->aac_daemontime); | |
| 984263bc MD |
273 | |
| 274 | /* | |
| e9ae7f4f | 275 | * Initialize the adapter. |
| 984263bc | 276 | */ |
| e9ae7f4f SW |
277 | if ((error = aac_alloc(sc)) != 0) |
| 278 | return(error); | |
| 984263bc MD |
279 | if ((error = aac_init(sc)) != 0) |
| 280 | return(error); | |
| 281 | ||
| d9773475 PA |
282 | /* |
| 283 | * Allocate and connect our interrupt. | |
| 984263bc | 284 | */ |
| e9ae7f4f SW |
285 | if ((error = aac_setup_intr(sc)) != 0) |
| 286 | return(error); | |
| 984263bc MD |
287 | |
| 288 | /* | |
| d9773475 | 289 | * Print a little information about the controller. |
| 984263bc | 290 | */ |
| d9773475 | 291 | aac_describe_controller(sc); |
| 984263bc MD |
292 | |
| 293 | /* | |
| d9773475 | 294 | * Register to probe our containers later. |
| 984263bc | 295 | */ |
| 984263bc MD |
296 | sc->aac_ich.ich_func = aac_startup; |
| 297 | sc->aac_ich.ich_arg = sc; | |
| 52800c9d | 298 | sc->aac_ich.ich_desc = "aac"; |
| 984263bc MD |
299 | if (config_intrhook_establish(&sc->aac_ich) != 0) { |
| 300 | device_printf(sc->aac_dev, | |
| 301 | "can't establish configuration hook\n"); | |
| 302 | return(ENXIO); | |
| 303 | } | |
| 304 | ||
| 305 | /* | |
| 306 | * Make the control device. | |
| 307 | */ | |
| 308 | unit = device_get_unit(sc->aac_dev); | |
| 3e82b46c MD |
309 | sc->aac_dev_t = make_dev(&aac_ops, unit, UID_ROOT, GID_OPERATOR, |
| 310 | 0640, "aac%d", unit); | |
| e9ae7f4f SW |
311 | (void)make_dev_alias(sc->aac_dev_t, "afa%d", unit); |
| 312 | (void)make_dev_alias(sc->aac_dev_t, "hpn%d", unit); | |
| 984263bc MD |
313 | sc->aac_dev_t->si_drv1 = sc; |
| 314 | ||
| 315 | /* Create the AIF thread */ | |
| cd8ab232 | 316 | if (kthread_create(aac_command_thread, sc, |
| 984263bc | 317 | &sc->aifthread, "aac%daif", unit)) |
| e9ae7f4f | 318 | panic("Could not create AIF thread"); |
| 984263bc MD |
319 | |
| 320 | /* Register the shutdown method to only be called post-dump */ | |
| e9ae7f4f SW |
321 | if ((sc->eh = EVENTHANDLER_REGISTER(shutdown_final, aac_shutdown, |
| 322 | sc->aac_dev, SHUTDOWN_PRI_DEFAULT)) == NULL) | |
| d9773475 PA |
323 | device_printf(sc->aac_dev, |
| 324 | "shutdown event registration failed\n"); | |
| 984263bc MD |
325 | |
| 326 | /* Register with CAM for the non-DASD devices */ | |
| d9773475 PA |
327 | if ((sc->flags & AAC_FLAGS_ENABLE_CAM) != 0) { |
| 328 | TAILQ_INIT(&sc->aac_sim_tqh); | |
| 984263bc | 329 | aac_get_bus_info(sc); |
| d9773475 | 330 | } |
| 984263bc | 331 | |
| e9ae7f4f SW |
332 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 333 | callout_reset(&sc->aac_daemontime, 60 * hz, aac_daemon, sc); | |
| 334 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 335 | ||
| 984263bc MD |
336 | return(0); |
| 337 | } | |
| 338 | ||
| e9ae7f4f SW |
339 | static void |
| 340 | aac_daemon(void *arg) | |
| 341 | { | |
| 342 | struct timeval tv; | |
| 343 | struct aac_softc *sc; | |
| 344 | struct aac_fib *fib; | |
| 345 | ||
| 346 | sc = arg; | |
| 347 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); | |
| 348 | ||
| 349 | if (callout_pending(&sc->aac_daemontime) || | |
| 350 | callout_active(&sc->aac_daemontime) == 0) | |
| 351 | return; | |
| 352 | getmicrotime(&tv); | |
| 353 | aac_alloc_sync_fib(sc, &fib); | |
| 354 | *(uint32_t *)fib->data = tv.tv_sec; | |
| 355 | aac_sync_fib(sc, SendHostTime, 0, fib, sizeof(uint32_t)); | |
| 356 | aac_release_sync_fib(sc); | |
| 357 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 358 | callout_reset(&sc->aac_daemontime, 30 * 60 * hz, aac_daemon, sc); | |
| 359 | } | |
| 360 | ||
| d9773475 PA |
361 | void |
| 362 | aac_add_event(struct aac_softc *sc, struct aac_event *event) | |
| 363 | { | |
| 364 | ||
| 365 | switch (event->ev_type & AAC_EVENT_MASK) { | |
| 366 | case AAC_EVENT_CMFREE: | |
| 367 | TAILQ_INSERT_TAIL(&sc->aac_ev_cmfree, event, ev_links); | |
| 368 | break; | |
| 369 | default: | |
| 370 | device_printf(sc->aac_dev, "aac_add event: unknown event %d\n", | |
| 371 | event->ev_type); | |
| 372 | break; | |
| 373 | } | |
| 374 | ||
| 375 | return; | |
| 376 | } | |
| 377 | ||
| 984263bc | 378 | /* |
| e9ae7f4f SW |
379 | * Request information of container #cid |
| 380 | */ | |
| 381 | static struct aac_mntinforesp * | |
| 382 | aac_get_container_info(struct aac_softc *sc, struct aac_fib *fib, int cid) | |
| 383 | { | |
| 384 | struct aac_mntinfo *mi; | |
| 385 | ||
| 386 | mi = (struct aac_mntinfo *)&fib->data[0]; | |
| 387 | /* use 64-bit LBA if enabled */ | |
| 388 | mi->Command = (sc->flags & AAC_FLAGS_LBA_64BIT) ? | |
| 389 | VM_NameServe64 : VM_NameServe; | |
| 390 | mi->MntType = FT_FILESYS; | |
| 391 | mi->MntCount = cid; | |
| 392 | ||
| 393 | if (aac_sync_fib(sc, ContainerCommand, 0, fib, | |
| 394 | sizeof(struct aac_mntinfo))) { | |
| 395 | device_printf(sc->aac_dev, "Error probing container %d\n", cid); | |
| 396 | return (NULL); | |
| 397 | } | |
| 398 | ||
| 399 | return ((struct aac_mntinforesp *)&fib->data[0]); | |
| 400 | } | |
| 401 | ||
| 402 | /* | |
| 984263bc MD |
403 | * Probe for containers, create disks. |
| 404 | */ | |
| 405 | static void | |
| 406 | aac_startup(void *arg) | |
| 407 | { | |
| 408 | struct aac_softc *sc; | |
| 409 | struct aac_fib *fib; | |
| e9ae7f4f | 410 | struct aac_mntinforesp *mir; |
| 158dbeb8 | 411 | int count = 0, i = 0; |
| 984263bc MD |
412 | |
| 413 | sc = (struct aac_softc *)arg; | |
| e9ae7f4f | 414 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
415 | |
| 416 | /* disconnect ourselves from the intrhook chain */ | |
| 417 | config_intrhook_disestablish(&sc->aac_ich); | |
| 418 | ||
| e9ae7f4f | 419 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 | 420 | aac_alloc_sync_fib(sc, &fib); |
| 984263bc MD |
421 | |
| 422 | /* loop over possible containers */ | |
| 423 | do { | |
| e9ae7f4f | 424 | if ((mir = aac_get_container_info(sc, fib, i)) == NULL) |
| 984263bc | 425 | continue; |
| e9ae7f4f SW |
426 | if (i == 0) |
| 427 | count = mir->MntRespCount; | |
| 984263bc MD |
428 | aac_add_container(sc, mir, 0); |
| 429 | i++; | |
| 158dbeb8 | 430 | } while ((i < count) && (i < AAC_MAX_CONTAINERS)); |
| 984263bc MD |
431 | |
| 432 | aac_release_sync_fib(sc); | |
| e9ae7f4f | 433 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc MD |
434 | |
| 435 | /* poke the bus to actually attach the child devices */ | |
| 436 | if (bus_generic_attach(sc->aac_dev)) | |
| 437 | device_printf(sc->aac_dev, "bus_generic_attach failed\n"); | |
| 438 | ||
| 439 | /* mark the controller up */ | |
| 440 | sc->aac_state &= ~AAC_STATE_SUSPEND; | |
| 441 | ||
| 442 | /* enable interrupts now */ | |
| 443 | AAC_UNMASK_INTERRUPTS(sc); | |
| 984263bc MD |
444 | } |
| 445 | ||
| 446 | /* | |
| e9ae7f4f | 447 | * Create a device to represent a new container |
| 984263bc MD |
448 | */ |
| 449 | static void | |
| 450 | aac_add_container(struct aac_softc *sc, struct aac_mntinforesp *mir, int f) | |
| 451 | { | |
| 452 | struct aac_container *co; | |
| 453 | device_t child; | |
| 454 | ||
| d9773475 | 455 | /* |
| 984263bc MD |
456 | * Check container volume type for validity. Note that many of |
| 457 | * the possible types may never show up. | |
| 458 | */ | |
| 459 | if ((mir->Status == ST_OK) && (mir->MntTable[0].VolType != CT_NONE)) { | |
| d9773475 PA |
460 | co = (struct aac_container *)kmalloc(sizeof *co, M_AACBUF, |
| 461 | M_INTWAIT | M_ZERO); | |
| e9ae7f4f | 462 | fwprintf(sc, HBA_FLAGS_DBG_INIT_B, "id %x name '%.16s' size %u type %d", |
| 984263bc MD |
463 | mir->MntTable[0].ObjectId, |
| 464 | mir->MntTable[0].FileSystemName, | |
| 465 | mir->MntTable[0].Capacity, mir->MntTable[0].VolType); | |
| d9773475 | 466 | |
| 984263bc MD |
467 | if ((child = device_add_child(sc->aac_dev, "aacd", -1)) == NULL) |
| 468 | device_printf(sc->aac_dev, "device_add_child failed\n"); | |
| 469 | else | |
| 470 | device_set_ivars(child, co); | |
| 471 | device_set_desc(child, aac_describe_code(aac_container_types, | |
| 472 | mir->MntTable[0].VolType)); | |
| 473 | co->co_disk = child; | |
| 474 | co->co_found = f; | |
| 475 | bcopy(&mir->MntTable[0], &co->co_mntobj, | |
| 476 | sizeof(struct aac_mntobj)); | |
| e9ae7f4f | 477 | lockmgr(&sc->aac_container_lock, LK_EXCLUSIVE); |
| 984263bc | 478 | TAILQ_INSERT_TAIL(&sc->aac_container_tqh, co, co_link); |
| e9ae7f4f SW |
479 | lockmgr(&sc->aac_container_lock, LK_RELEASE); |
| 480 | } | |
| 481 | } | |
| 482 | ||
| 483 | /* | |
| 484 | * Allocate resources associated with (sc) | |
| 485 | */ | |
| 486 | static int | |
| 487 | aac_alloc(struct aac_softc *sc) | |
| 488 | { | |
| 489 | ||
| 490 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 491 | ||
| 492 | /* | |
| 493 | * Create DMA tag for mapping buffers into controller-addressable space. | |
| 494 | */ | |
| 495 | if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ | |
| 496 | 1, 0, /* algnmnt, boundary */ | |
| 497 | (sc->flags & AAC_FLAGS_SG_64BIT) ? | |
| 498 | BUS_SPACE_MAXADDR : | |
| 499 | BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ | |
| 500 | BUS_SPACE_MAXADDR, /* highaddr */ | |
| 501 | NULL, NULL, /* filter, filterarg */ | |
| 502 | MAXBSIZE, /* maxsize */ | |
| 503 | sc->aac_sg_tablesize, /* nsegments */ | |
| 504 | MAXBSIZE, /* maxsegsize */ | |
| 505 | BUS_DMA_ALLOCNOW, /* flags */ | |
| 506 | &sc->aac_buffer_dmat)) { | |
| 507 | device_printf(sc->aac_dev, "can't allocate buffer DMA tag\n"); | |
| 508 | return (ENOMEM); | |
| 509 | } | |
| 510 | ||
| 511 | /* | |
| 512 | * Create DMA tag for mapping FIBs into controller-addressable space.. | |
| 513 | */ | |
| 514 | if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ | |
| 515 | 1, 0, /* algnmnt, boundary */ | |
| 516 | (sc->flags & AAC_FLAGS_4GB_WINDOW) ? | |
| 517 | BUS_SPACE_MAXADDR_32BIT : | |
| 518 | 0x7fffffff, /* lowaddr */ | |
| 519 | BUS_SPACE_MAXADDR, /* highaddr */ | |
| 520 | NULL, NULL, /* filter, filterarg */ | |
| 521 | sc->aac_max_fibs_alloc * | |
| 522 | sc->aac_max_fib_size, /* maxsize */ | |
| 523 | 1, /* nsegments */ | |
| 524 | sc->aac_max_fibs_alloc * | |
| 525 | sc->aac_max_fib_size, /* maxsize */ | |
| 526 | 0, /* flags */ | |
| 527 | &sc->aac_fib_dmat)) { | |
| 528 | device_printf(sc->aac_dev, "can't allocate FIB DMA tag\n"); | |
| 529 | return (ENOMEM); | |
| 984263bc | 530 | } |
| e9ae7f4f SW |
531 | |
| 532 | /* | |
| 533 | * Create DMA tag for the common structure and allocate it. | |
| 534 | */ | |
| 535 | if (bus_dma_tag_create(sc->aac_parent_dmat, /* parent */ | |
| 536 | 1, 0, /* algnmnt, boundary */ | |
| 537 | (sc->flags & AAC_FLAGS_4GB_WINDOW) ? | |
| 538 | BUS_SPACE_MAXADDR_32BIT : | |
| 539 | 0x7fffffff, /* lowaddr */ | |
| 540 | BUS_SPACE_MAXADDR, /* highaddr */ | |
| 541 | NULL, NULL, /* filter, filterarg */ | |
| 542 | 8192 + sizeof(struct aac_common), /* maxsize */ | |
| 543 | 1, /* nsegments */ | |
| 544 | BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ | |
| 545 | 0, /* flags */ | |
| 546 | &sc->aac_common_dmat)) { | |
| 547 | device_printf(sc->aac_dev, | |
| 548 | "can't allocate common structure DMA tag\n"); | |
| 549 | return (ENOMEM); | |
| 550 | } | |
| 551 | if (bus_dmamem_alloc(sc->aac_common_dmat, (void **)&sc->aac_common, | |
| 552 | BUS_DMA_NOWAIT, &sc->aac_common_dmamap)) { | |
| 553 | device_printf(sc->aac_dev, "can't allocate common structure\n"); | |
| 554 | return (ENOMEM); | |
| 555 | } | |
| 556 | ||
| 557 | /* | |
| 558 | * Work around a bug in the 2120 and 2200 that cannot DMA commands | |
| 559 | * below address 8192 in physical memory. | |
| 560 | * XXX If the padding is not needed, can it be put to use instead | |
| 561 | * of ignored? | |
| 562 | */ | |
| 563 | (void)bus_dmamap_load(sc->aac_common_dmat, sc->aac_common_dmamap, | |
| 564 | sc->aac_common, 8192 + sizeof(*sc->aac_common), | |
| 565 | aac_common_map, sc, 0); | |
| 566 | ||
| 567 | if (sc->aac_common_busaddr < 8192) { | |
| 568 | sc->aac_common = (struct aac_common *) | |
| 569 | ((uint8_t *)sc->aac_common + 8192); | |
| 570 | sc->aac_common_busaddr += 8192; | |
| 571 | } | |
| 572 | bzero(sc->aac_common, sizeof(*sc->aac_common)); | |
| 573 | ||
| 574 | /* Allocate some FIBs and associated command structs */ | |
| 575 | TAILQ_INIT(&sc->aac_fibmap_tqh); | |
| 576 | sc->aac_commands = kmalloc(sc->aac_max_fibs * sizeof(struct aac_command), | |
| 577 | M_AACBUF, M_WAITOK|M_ZERO); | |
| 578 | while (sc->total_fibs < sc->aac_max_fibs) { | |
| 579 | if (aac_alloc_commands(sc) != 0) | |
| 580 | break; | |
| 581 | } | |
| 582 | if (sc->total_fibs == 0) | |
| 583 | return (ENOMEM); | |
| 584 | ||
| 585 | return (0); | |
| 984263bc MD |
586 | } |
| 587 | ||
| 588 | /* | |
| 589 | * Free all of the resources associated with (sc) | |
| 590 | * | |
| 591 | * Should not be called if the controller is active. | |
| 592 | */ | |
| 593 | void | |
| 594 | aac_free(struct aac_softc *sc) | |
| 595 | { | |
| d9773475 | 596 | |
| e9ae7f4f | 597 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
598 | |
| 599 | /* remove the control device */ | |
| 600 | if (sc->aac_dev_t != NULL) | |
| 601 | destroy_dev(sc->aac_dev_t); | |
| 602 | ||
| 603 | /* throw away any FIB buffers, discard the FIB DMA tag */ | |
| d9773475 | 604 | aac_free_commands(sc); |
| 984263bc MD |
605 | if (sc->aac_fib_dmat) |
| 606 | bus_dma_tag_destroy(sc->aac_fib_dmat); | |
| 607 | ||
| d9773475 PA |
608 | kfree(sc->aac_commands, M_AACBUF); |
| 609 | ||
| 984263bc MD |
610 | /* destroy the common area */ |
| 611 | if (sc->aac_common) { | |
| 612 | bus_dmamap_unload(sc->aac_common_dmat, sc->aac_common_dmamap); | |
| 613 | bus_dmamem_free(sc->aac_common_dmat, sc->aac_common, | |
| 614 | sc->aac_common_dmamap); | |
| 615 | } | |
| 616 | if (sc->aac_common_dmat) | |
| 617 | bus_dma_tag_destroy(sc->aac_common_dmat); | |
| 618 | ||
| 619 | /* disconnect the interrupt handler */ | |
| 620 | if (sc->aac_intr) | |
| 621 | bus_teardown_intr(sc->aac_dev, sc->aac_irq, sc->aac_intr); | |
| 622 | if (sc->aac_irq != NULL) | |
| 623 | bus_release_resource(sc->aac_dev, SYS_RES_IRQ, sc->aac_irq_rid, | |
| 624 | sc->aac_irq); | |
| 625 | ||
| 626 | /* destroy data-transfer DMA tag */ | |
| 627 | if (sc->aac_buffer_dmat) | |
| 628 | bus_dma_tag_destroy(sc->aac_buffer_dmat); | |
| 629 | ||
| 630 | /* destroy the parent DMA tag */ | |
| 631 | if (sc->aac_parent_dmat) | |
| 632 | bus_dma_tag_destroy(sc->aac_parent_dmat); | |
| 633 | ||
| 634 | /* release the register window mapping */ | |
| e9ae7f4f | 635 | if (sc->aac_regs_res0 != NULL) |
| 984263bc | 636 | bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, |
| e9ae7f4f SW |
637 | sc->aac_regs_rid0, sc->aac_regs_res0); |
| 638 | if (sc->aac_hwif == AAC_HWIF_NARK && sc->aac_regs_res1 != NULL) | |
| 639 | bus_release_resource(sc->aac_dev, SYS_RES_MEMORY, | |
| 640 | sc->aac_regs_rid1, sc->aac_regs_res1); | |
| cd29885a | 641 | dev_ops_remove_minor(&aac_ops, device_get_unit(sc->aac_dev)); |
| 984263bc MD |
642 | } |
| 643 | ||
| 644 | /* | |
| 645 | * Disconnect from the controller completely, in preparation for unload. | |
| 646 | */ | |
| 647 | int | |
| 648 | aac_detach(device_t dev) | |
| 649 | { | |
| 650 | struct aac_softc *sc; | |
| d9773475 PA |
651 | struct aac_container *co; |
| 652 | struct aac_sim *sim; | |
| 984263bc | 653 | int error; |
| 984263bc | 654 | |
| 984263bc | 655 | sc = device_get_softc(dev); |
| e9ae7f4f | 656 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 657 | |
| e9ae7f4f | 658 | callout_stop(&sc->aac_daemontime); |
| d9773475 PA |
659 | |
| 660 | /* Remove the child containers */ | |
| 661 | while ((co = TAILQ_FIRST(&sc->aac_container_tqh)) != NULL) { | |
| 662 | error = device_delete_child(dev, co->co_disk); | |
| 663 | if (error) | |
| 664 | return (error); | |
| 665 | TAILQ_REMOVE(&sc->aac_container_tqh, co, co_link); | |
| 666 | kfree(co, M_AACBUF); | |
| 667 | } | |
| 668 | ||
| 669 | /* Remove the CAM SIMs */ | |
| 670 | while ((sim = TAILQ_FIRST(&sc->aac_sim_tqh)) != NULL) { | |
| 671 | TAILQ_REMOVE(&sc->aac_sim_tqh, sim, sim_link); | |
| 672 | error = device_delete_child(dev, sim->sim_dev); | |
| 673 | if (error) | |
| 674 | return (error); | |
| 675 | kfree(sim, M_AACBUF); | |
| 676 | } | |
| 984263bc | 677 | |
| 984263bc MD |
678 | if (sc->aifflags & AAC_AIFFLAGS_RUNNING) { |
| 679 | sc->aifflags |= AAC_AIFFLAGS_EXIT; | |
| 680 | wakeup(sc->aifthread); | |
| 377d4740 | 681 | tsleep(sc->aac_dev, PCATCH, "aacdch", 30 * hz); |
| 984263bc MD |
682 | } |
| 683 | ||
| 684 | if (sc->aifflags & AAC_AIFFLAGS_RUNNING) | |
| e9ae7f4f | 685 | panic("Cannot shutdown AIF thread"); |
| 984263bc MD |
686 | |
| 687 | if ((error = aac_shutdown(dev))) | |
| 688 | return(error); | |
| 689 | ||
| e9ae7f4f | 690 | EVENTHANDLER_DEREGISTER(shutdown_final, sc->eh); |
| d9773475 | 691 | |
| 984263bc MD |
692 | aac_free(sc); |
| 693 | ||
| d9773475 PA |
694 | lockuninit(&sc->aac_aifq_lock); |
| 695 | lockuninit(&sc->aac_io_lock); | |
| 696 | lockuninit(&sc->aac_container_lock); | |
| 697 | ||
| 984263bc | 698 | return(0); |
| 984263bc MD |
699 | } |
| 700 | ||
| 701 | /* | |
| 702 | * Bring the controller down to a dormant state and detach all child devices. | |
| 703 | * | |
| 704 | * This function is called before detach or system shutdown. | |
| 705 | * | |
| 706 | * Note that we can assume that the bioq on the controller is empty, as we won't | |
| 707 | * allow shutdown if any device is open. | |
| 708 | */ | |
| e9ae7f4f | 709 | int |
| 984263bc MD |
710 | aac_shutdown(device_t dev) |
| 711 | { | |
| 712 | struct aac_softc *sc; | |
| 713 | struct aac_fib *fib; | |
| 714 | struct aac_close_command *cc; | |
| 984263bc | 715 | |
| 984263bc | 716 | sc = device_get_softc(dev); |
| e9ae7f4f | 717 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 718 | |
| 984263bc MD |
719 | sc->aac_state |= AAC_STATE_SUSPEND; |
| 720 | ||
| d9773475 | 721 | /* |
| 984263bc MD |
722 | * Send a Container shutdown followed by a HostShutdown FIB to the |
| 723 | * controller to convince it that we don't want to talk to it anymore. | |
| 724 | * We've been closed and all I/O completed already | |
| 725 | */ | |
| 726 | device_printf(sc->aac_dev, "shutting down controller..."); | |
| 727 | ||
| e9ae7f4f | 728 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 | 729 | aac_alloc_sync_fib(sc, &fib); |
| 984263bc MD |
730 | cc = (struct aac_close_command *)&fib->data[0]; |
| 731 | ||
| 732 | bzero(cc, sizeof(struct aac_close_command)); | |
| 733 | cc->Command = VM_CloseAll; | |
| 734 | cc->ContainerId = 0xffffffff; | |
| 735 | if (aac_sync_fib(sc, ContainerCommand, 0, fib, | |
| 736 | sizeof(struct aac_close_command))) | |
| e3869ec7 | 737 | kprintf("FAILED.\n"); |
| d9773475 PA |
738 | else |
| 739 | kprintf("done\n"); | |
| 740 | #if 0 | |
| 984263bc MD |
741 | else { |
| 742 | fib->data[0] = 0; | |
| 743 | /* | |
| 744 | * XXX Issuing this command to the controller makes it shut down | |
| 745 | * but also keeps it from coming back up without a reset of the | |
| 746 | * PCI bus. This is not desirable if you are just unloading the | |
| 747 | * driver module with the intent to reload it later. | |
| 748 | */ | |
| 749 | if (aac_sync_fib(sc, FsaHostShutdown, AAC_FIBSTATE_SHUTDOWN, | |
| 750 | fib, 1)) { | |
| e3869ec7 | 751 | kprintf("FAILED.\n"); |
| 984263bc | 752 | } else { |
| e3869ec7 | 753 | kprintf("done.\n"); |
| 984263bc MD |
754 | } |
| 755 | } | |
| d9773475 | 756 | #endif |
| 984263bc MD |
757 | |
| 758 | AAC_MASK_INTERRUPTS(sc); | |
| d9773475 | 759 | aac_release_sync_fib(sc); |
| e9ae7f4f | 760 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc | 761 | |
| 984263bc MD |
762 | return(0); |
| 763 | } | |
| 764 | ||
| 765 | /* | |
| 766 | * Bring the controller to a quiescent state, ready for system suspend. | |
| 767 | */ | |
| 768 | int | |
| 769 | aac_suspend(device_t dev) | |
| 770 | { | |
| 771 | struct aac_softc *sc; | |
| 984263bc | 772 | |
| 984263bc MD |
773 | sc = device_get_softc(dev); |
| 774 | ||
| e9ae7f4f | 775 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 776 | sc->aac_state |= AAC_STATE_SUSPEND; |
| d9773475 | 777 | |
| 984263bc | 778 | AAC_MASK_INTERRUPTS(sc); |
| 984263bc MD |
779 | return(0); |
| 780 | } | |
| 781 | ||
| 782 | /* | |
| 783 | * Bring the controller back to a state ready for operation. | |
| 784 | */ | |
| 785 | int | |
| 786 | aac_resume(device_t dev) | |
| 787 | { | |
| 788 | struct aac_softc *sc; | |
| 789 | ||
| 984263bc MD |
790 | sc = device_get_softc(dev); |
| 791 | ||
| e9ae7f4f | 792 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
793 | sc->aac_state &= ~AAC_STATE_SUSPEND; |
| 794 | AAC_UNMASK_INTERRUPTS(sc); | |
| 795 | return(0); | |
| 796 | } | |
| 797 | ||
| 798 | /* | |
| d9773475 | 799 | * Interrupt handler for NEW_COMM interface. |
| 984263bc MD |
800 | */ |
| 801 | void | |
| d9773475 PA |
802 | aac_new_intr(void *arg) |
| 803 | { | |
| 804 | struct aac_softc *sc; | |
| 805 | u_int32_t index, fast; | |
| 806 | struct aac_command *cm; | |
| 807 | struct aac_fib *fib; | |
| 808 | int i; | |
| 809 | ||
| d9773475 PA |
810 | sc = (struct aac_softc *)arg; |
| 811 | ||
| e9ae7f4f SW |
812 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 813 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); | |
| d9773475 PA |
814 | while (1) { |
| 815 | index = AAC_GET_OUTB_QUEUE(sc); | |
| 816 | if (index == 0xffffffff) | |
| 817 | index = AAC_GET_OUTB_QUEUE(sc); | |
| 818 | if (index == 0xffffffff) | |
| 819 | break; | |
| 820 | if (index & 2) { | |
| 821 | if (index == 0xfffffffe) { | |
| 822 | /* XXX This means that the controller wants | |
| 823 | * more work. Ignore it for now. | |
| 824 | */ | |
| 825 | continue; | |
| 826 | } | |
| 827 | /* AIF */ | |
| 828 | fib = (struct aac_fib *)kmalloc(sizeof *fib, M_AACBUF, | |
| 829 | M_INTWAIT | M_ZERO); | |
| 830 | index &= ~2; | |
| 831 | for (i = 0; i < sizeof(struct aac_fib)/4; ++i) | |
| e9ae7f4f | 832 | ((u_int32_t *)fib)[i] = AAC_MEM1_GETREG4(sc, index + i*4); |
| d9773475 PA |
833 | aac_handle_aif(sc, fib); |
| 834 | kfree(fib, M_AACBUF); | |
| 835 | ||
| 836 | /* | |
| 837 | * AIF memory is owned by the adapter, so let it | |
| 838 | * know that we are done with it. | |
| 839 | */ | |
| 840 | AAC_SET_OUTB_QUEUE(sc, index); | |
| 841 | AAC_CLEAR_ISTATUS(sc, AAC_DB_RESPONSE_READY); | |
| 842 | } else { | |
| 843 | fast = index & 1; | |
| 844 | cm = sc->aac_commands + (index >> 2); | |
| 845 | fib = cm->cm_fib; | |
| 846 | if (fast) { | |
| 847 | fib->Header.XferState |= AAC_FIBSTATE_DONEADAP; | |
| 848 | *((u_int32_t *)(fib->data)) = AAC_ERROR_NORMAL; | |
| 849 | } | |
| 850 | aac_remove_busy(cm); | |
| 851 | aac_unmap_command(cm); | |
| 852 | cm->cm_flags |= AAC_CMD_COMPLETED; | |
| 853 | ||
| 854 | /* is there a completion handler? */ | |
| 855 | if (cm->cm_complete != NULL) { | |
| 856 | cm->cm_complete(cm); | |
| 857 | } else { | |
| 858 | /* assume that someone is sleeping on this | |
| 859 | * command | |
| 860 | */ | |
| 861 | wakeup(cm); | |
| 862 | } | |
| 863 | sc->flags &= ~AAC_QUEUE_FRZN; | |
| 864 | } | |
| 865 | } | |
| 866 | /* see if we can start some more I/O */ | |
| 867 | if ((sc->flags & AAC_QUEUE_FRZN) == 0) | |
| 868 | aac_startio(sc); | |
| 869 | ||
| e9ae7f4f | 870 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| d9773475 PA |
871 | } |
| 872 | ||
| e9ae7f4f SW |
873 | /* |
| 874 | * Interrupt filter for !NEW_COMM interface. | |
| 875 | */ | |
| d9773475 | 876 | void |
| e9ae7f4f | 877 | aac_filter(void *arg) |
| 984263bc MD |
878 | { |
| 879 | struct aac_softc *sc; | |
| 880 | u_int16_t reason; | |
| 984263bc | 881 | |
| 984263bc MD |
882 | sc = (struct aac_softc *)arg; |
| 883 | ||
| e9ae7f4f | 884 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 885 | /* |
| d9773475 PA |
886 | * Read the status register directly. This is faster than taking the |
| 887 | * driver lock and reading the queues directly. It also saves having | |
| 888 | * to turn parts of the driver lock into a spin mutex, which would be | |
| 889 | * ugly. | |
| 984263bc | 890 | */ |
| d9773475 | 891 | reason = AAC_GET_ISTATUS(sc); |
| 984263bc | 892 | AAC_CLEAR_ISTATUS(sc, reason); |
| 984263bc | 893 | |
| d9773475 | 894 | /* handle completion processing */ |
| 984263bc | 895 | if (reason & AAC_DB_RESPONSE_READY) |
| d9773475 | 896 | taskqueue_enqueue(taskqueue_swi, &sc->aac_task_complete); |
| 984263bc | 897 | |
| d9773475 PA |
898 | /* controller wants to talk to us */ |
| 899 | if (reason & (AAC_DB_PRINTF | AAC_DB_COMMAND_READY)) { | |
| 900 | /* | |
| 901 | * XXX Make sure that we don't get fooled by strange messages | |
| 902 | * that start with a NULL. | |
| 903 | */ | |
| 904 | if ((reason & AAC_DB_PRINTF) && | |
| 905 | (sc->aac_common->ac_printf[0] == 0)) | |
| 906 | sc->aac_common->ac_printf[0] = 32; | |
| 984263bc | 907 | |
| d9773475 PA |
908 | /* |
| 909 | * This might miss doing the actual wakeup. However, the | |
| e9ae7f4f | 910 | * lksleep that this is waking up has a timeout, so it will |
| d9773475 PA |
911 | * wake up eventually. AIFs and printfs are low enough |
| 912 | * priority that they can handle hanging out for a few seconds | |
| 913 | * if needed. | |
| 914 | */ | |
| 915 | wakeup(sc->aifthread); | |
| 984263bc MD |
916 | } |
| 917 | } | |
| 918 | ||
| 919 | /* | |
| 920 | * Command Processing | |
| 921 | */ | |
| 922 | ||
| 923 | /* | |
| 924 | * Start as much queued I/O as possible on the controller | |
| 925 | */ | |
| 926 | void | |
| 927 | aac_startio(struct aac_softc *sc) | |
| 928 | { | |
| 929 | struct aac_command *cm; | |
| e9ae7f4f | 930 | int error; |
| 984263bc | 931 | |
| e9ae7f4f | 932 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 933 | |
| 984263bc MD |
934 | for (;;) { |
| 935 | /* | |
| e9ae7f4f SW |
936 | * This flag might be set if the card is out of resources. |
| 937 | * Checking it here prevents an infinite loop of deferrals. | |
| 938 | */ | |
| 939 | if (sc->flags & AAC_QUEUE_FRZN) | |
| 940 | break; | |
| 941 | ||
| 942 | /* | |
| d9773475 | 943 | * Try to get a command that's been put off for lack of |
| 984263bc MD |
944 | * resources |
| 945 | */ | |
| 946 | cm = aac_dequeue_ready(sc); | |
| 947 | ||
| 948 | /* | |
| d9773475 | 949 | * Try to build a command off the bio queue (ignore error |
| 984263bc MD |
950 | * return) |
| 951 | */ | |
| 952 | if (cm == NULL) | |
| 953 | aac_bio_command(sc, &cm); | |
| 954 | ||
| 955 | /* nothing to do? */ | |
| 956 | if (cm == NULL) | |
| 957 | break; | |
| 958 | ||
| e9ae7f4f SW |
959 | /* don't map more than once */ |
| 960 | if (cm->cm_flags & AAC_CMD_MAPPED) | |
| 961 | panic("aac: command %p already mapped", cm); | |
| 962 | ||
| d9773475 | 963 | /* |
| e9ae7f4f SW |
964 | * Set up the command to go to the controller. If there are no |
| 965 | * data buffers associated with the command then it can bypass | |
| 966 | * busdma. | |
| d9773475 | 967 | */ |
| e9ae7f4f SW |
968 | if (cm->cm_datalen != 0) { |
| 969 | error = bus_dmamap_load(sc->aac_buffer_dmat, | |
| 970 | cm->cm_datamap, cm->cm_data, | |
| 971 | cm->cm_datalen, | |
| 972 | aac_map_command_sg, cm, 0); | |
| 973 | if (error == EINPROGRESS) { | |
| 974 | fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "freezing queue\n"); | |
| 975 | sc->flags |= AAC_QUEUE_FRZN; | |
| 976 | error = 0; | |
| 977 | } else if (error != 0) | |
| 978 | panic("aac_startio: unexpected error %d from " | |
| 979 | "busdma", error); | |
| 980 | } else | |
| 981 | aac_map_command_sg(cm, NULL, 0, 0); | |
| d9773475 | 982 | } |
| 984263bc MD |
983 | } |
| 984 | ||
| 985 | /* | |
| 986 | * Handle notification of one or more FIBs coming from the controller. | |
| 987 | */ | |
| 988 | static void | |
| cd8ab232 | 989 | aac_command_thread(void *arg) |
| 984263bc | 990 | { |
| cd8ab232 | 991 | struct aac_softc *sc = arg; |
| 984263bc MD |
992 | struct aac_fib *fib; |
| 993 | u_int32_t fib_size; | |
| d9773475 | 994 | int size, retval; |
| 984263bc | 995 | |
| e9ae7f4f | 996 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 997 | |
| e9ae7f4f | 998 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 | 999 | sc->aifflags = AAC_AIFFLAGS_RUNNING; |
| 984263bc | 1000 | |
| d9773475 | 1001 | while ((sc->aifflags & AAC_AIFFLAGS_EXIT) == 0) { |
| e9ae7f4f | 1002 | |
| d9773475 | 1003 | retval = 0; |
| e9ae7f4f SW |
1004 | if ((sc->aifflags & AAC_AIFFLAGS_PENDING) == 0) |
| 1005 | retval = lksleep(sc->aifthread, &sc->aac_io_lock, 0, | |
| d9773475 | 1006 | "aifthd", AAC_PERIODIC_INTERVAL * hz); |
| e9ae7f4f | 1007 | |
| d9773475 PA |
1008 | /* |
| 1009 | * First see if any FIBs need to be allocated. This needs | |
| 1010 | * to be called without the driver lock because contigmalloc | |
| 1011 | * will grab Giant, and would result in an LOR. | |
| 1012 | */ | |
| 1013 | if ((sc->aifflags & AAC_AIFFLAGS_ALLOCFIBS) != 0) { | |
| e9ae7f4f | 1014 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| d9773475 | 1015 | aac_alloc_commands(sc); |
| e9ae7f4f | 1016 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 PA |
1017 | sc->aifflags &= ~AAC_AIFFLAGS_ALLOCFIBS; |
| 1018 | aac_startio(sc); | |
| 1019 | } | |
| 984263bc | 1020 | |
| d9773475 PA |
1021 | /* |
| 1022 | * While we're here, check to see if any commands are stuck. | |
| 1023 | * This is pretty low-priority, so it's ok if it doesn't | |
| 1024 | * always fire. | |
| 1025 | */ | |
| 1026 | if (retval == EWOULDBLOCK) | |
| 1027 | aac_timeout(sc); | |
| 1028 | ||
| 1029 | /* Check the hardware printf message buffer */ | |
| 1030 | if (sc->aac_common->ac_printf[0] != 0) | |
| 1031 | aac_print_printf(sc); | |
| 1032 | ||
| 1033 | /* Also check to see if the adapter has a command for us. */ | |
| 1034 | if (sc->flags & AAC_FLAGS_NEW_COMM) | |
| 1035 | continue; | |
| 984263bc MD |
1036 | for (;;) { |
| 1037 | if (aac_dequeue_fib(sc, AAC_HOST_NORM_CMD_QUEUE, | |
| e9ae7f4f | 1038 | &fib_size, &fib)) |
| d9773475 PA |
1039 | break; |
| 1040 | ||
| 984263bc | 1041 | AAC_PRINT_FIB(sc, fib); |
| d9773475 | 1042 | |
| 984263bc MD |
1043 | switch (fib->Header.Command) { |
| 1044 | case AifRequest: | |
| 1045 | aac_handle_aif(sc, fib); | |
| 1046 | break; | |
| 1047 | default: | |
| 1048 | device_printf(sc->aac_dev, "unknown command " | |
| 1049 | "from controller\n"); | |
| 1050 | break; | |
| 1051 | } | |
| 1052 | ||
| 984263bc | 1053 | if ((fib->Header.XferState == 0) || |
| d9773475 | 1054 | (fib->Header.StructType != AAC_FIBTYPE_TFIB)) { |
| 984263bc | 1055 | break; |
| d9773475 | 1056 | } |
| 984263bc | 1057 | |
| d9773475 | 1058 | /* Return the AIF to the controller. */ |
| 984263bc MD |
1059 | if (fib->Header.XferState & AAC_FIBSTATE_FROMADAP) { |
| 1060 | fib->Header.XferState |= AAC_FIBSTATE_DONEHOST; | |
| 1061 | *(AAC_FSAStatus*)fib->data = ST_OK; | |
| 1062 | ||
| 1063 | /* XXX Compute the Size field? */ | |
| 1064 | size = fib->Header.Size; | |
| 1065 | if (size > sizeof(struct aac_fib)) { | |
| 1066 | size = sizeof(struct aac_fib); | |
| 1067 | fib->Header.Size = size; | |
| 1068 | } | |
| 1069 | /* | |
| 1070 | * Since we did not generate this command, it | |
| 1071 | * cannot go through the normal | |
| 1072 | * enqueue->startio chain. | |
| 1073 | */ | |
| 1074 | aac_enqueue_response(sc, | |
| d9773475 PA |
1075 | AAC_ADAP_NORM_RESP_QUEUE, |
| 1076 | fib); | |
| 984263bc MD |
1077 | } |
| 1078 | } | |
| 1079 | } | |
| 1080 | sc->aifflags &= ~AAC_AIFFLAGS_RUNNING; | |
| e9ae7f4f | 1081 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc | 1082 | wakeup(sc->aac_dev); |
| 984263bc MD |
1083 | } |
| 1084 | ||
| 1085 | /* | |
| d9773475 | 1086 | * Process completed commands. |
| 984263bc MD |
1087 | */ |
| 1088 | static void | |
| d9773475 | 1089 | aac_complete(void *context, int pending) |
| 984263bc | 1090 | { |
| d9773475 | 1091 | struct aac_softc *sc; |
| 984263bc MD |
1092 | struct aac_command *cm; |
| 1093 | struct aac_fib *fib; | |
| 1094 | u_int32_t fib_size; | |
| 1095 | ||
| d9773475 | 1096 | sc = (struct aac_softc *)context; |
| e9ae7f4f | 1097 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 1098 | |
| e9ae7f4f | 1099 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 PA |
1100 | |
| 1101 | /* pull completed commands off the queue */ | |
| 984263bc MD |
1102 | for (;;) { |
| 1103 | /* look for completed FIBs on our queue */ | |
| 1104 | if (aac_dequeue_fib(sc, AAC_HOST_NORM_RESP_QUEUE, &fib_size, | |
| d9773475 | 1105 | &fib)) |
| 984263bc | 1106 | break; /* nothing to do */ |
| d9773475 | 1107 | |
| e9ae7f4f | 1108 | /* get the command, unmap and hand off for processing */ |
| d9773475 | 1109 | cm = sc->aac_commands + fib->Header.SenderData; |
| 984263bc MD |
1110 | if (cm == NULL) { |
| 1111 | AAC_PRINT_FIB(sc, fib); | |
| 984263bc | 1112 | break; |
| d9773475 | 1113 | } |
| e9ae7f4f SW |
1114 | if ((cm->cm_flags & AAC_CMD_TIMEDOUT) != 0) |
| 1115 | device_printf(sc->aac_dev, | |
| 1116 | "COMMAND %p COMPLETED AFTER %d SECONDS\n", | |
| 1117 | cm, (int)(time_second-cm->cm_timestamp)); | |
| 1118 | ||
| d9773475 | 1119 | aac_remove_busy(cm); |
| e9ae7f4f SW |
1120 | |
| 1121 | aac_unmap_command(cm); | |
| 984263bc MD |
1122 | cm->cm_flags |= AAC_CMD_COMPLETED; |
| 1123 | ||
| 1124 | /* is there a completion handler? */ | |
| 1125 | if (cm->cm_complete != NULL) { | |
| 1126 | cm->cm_complete(cm); | |
| 1127 | } else { | |
| 1128 | /* assume that someone is sleeping on this command */ | |
| 1129 | wakeup(cm); | |
| 1130 | } | |
| 1131 | } | |
| 1132 | ||
| 1133 | /* see if we can start some more I/O */ | |
| d9773475 | 1134 | sc->flags &= ~AAC_QUEUE_FRZN; |
| 984263bc | 1135 | aac_startio(sc); |
| d9773475 | 1136 | |
| e9ae7f4f | 1137 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc MD |
1138 | } |
| 1139 | ||
| 1140 | /* | |
| 1141 | * Handle a bio submitted from a disk device. | |
| 1142 | */ | |
| 1143 | void | |
| 81b5c339 | 1144 | aac_submit_bio(struct aac_disk *ad, struct bio *bio) |
| 984263bc | 1145 | { |
| 984263bc MD |
1146 | struct aac_softc *sc; |
| 1147 | ||
| 81b5c339 | 1148 | bio->bio_driver_info = ad; |
| 984263bc | 1149 | sc = ad->ad_controller; |
| e9ae7f4f | 1150 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
1151 | |
| 1152 | /* queue the BIO and try to get some work done */ | |
| 81b5c339 | 1153 | aac_enqueue_bio(sc, bio); |
| 984263bc MD |
1154 | aac_startio(sc); |
| 1155 | } | |
| 1156 | ||
| 1157 | /* | |
| 1158 | * Get a bio and build a command to go with it. | |
| 1159 | */ | |
| 1160 | static int | |
| 1161 | aac_bio_command(struct aac_softc *sc, struct aac_command **cmp) | |
| 1162 | { | |
| 1163 | struct aac_command *cm; | |
| 1164 | struct aac_fib *fib; | |
| 984263bc | 1165 | struct aac_disk *ad; |
| 81b5c339 | 1166 | struct bio *bio; |
| 1eabbf32 | 1167 | struct buf *bp; |
| 984263bc | 1168 | |
| e9ae7f4f | 1169 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
1170 | |
| 1171 | /* get the resources we will need */ | |
| 1172 | cm = NULL; | |
| d9773475 | 1173 | bio = NULL; |
| 984263bc MD |
1174 | if (aac_alloc_command(sc, &cm)) /* get a command */ |
| 1175 | goto fail; | |
| d9773475 PA |
1176 | if ((bio = aac_dequeue_bio(sc)) == NULL) |
| 1177 | goto fail; | |
| 984263bc MD |
1178 | |
| 1179 | /* fill out the command */ | |
| 81b5c339 | 1180 | bp = bio->bio_buf; |
| 1eabbf32 HP |
1181 | cm->cm_data = (void *)bp->b_data; |
| 1182 | cm->cm_datalen = bp->b_bcount; | |
| 984263bc | 1183 | cm->cm_complete = aac_bio_complete; |
| 81b5c339 | 1184 | cm->cm_private = bio; |
| 984263bc | 1185 | cm->cm_timestamp = time_second; |
| 984263bc MD |
1186 | |
| 1187 | /* build the FIB */ | |
| 1188 | fib = cm->cm_fib; | |
| d9773475 PA |
1189 | fib->Header.Size = sizeof(struct aac_fib_header); |
| 1190 | fib->Header.XferState = | |
| 1191 | AAC_FIBSTATE_HOSTOWNED | | |
| 1192 | AAC_FIBSTATE_INITIALISED | | |
| 1193 | AAC_FIBSTATE_EMPTY | | |
| 984263bc MD |
1194 | AAC_FIBSTATE_FROMHOST | |
| 1195 | AAC_FIBSTATE_REXPECTED | | |
| 1196 | AAC_FIBSTATE_NORM | | |
| 1197 | AAC_FIBSTATE_ASYNC | | |
| 1198 | AAC_FIBSTATE_FAST_RESPONSE; | |
| 984263bc MD |
1199 | |
| 1200 | /* build the read/write request */ | |
| 81b5c339 | 1201 | ad = (struct aac_disk *)bio->bio_driver_info; |
| d9773475 PA |
1202 | |
| 1203 | if (sc->flags & AAC_FLAGS_RAW_IO) { | |
| 1204 | struct aac_raw_io *raw; | |
| 1205 | raw = (struct aac_raw_io *)&fib->data[0]; | |
| 1206 | fib->Header.Command = RawIo; | |
| 1207 | raw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; | |
| 1208 | raw->ByteCount = bp->b_bcount; | |
| 1209 | raw->ContainerId = ad->ad_container->co_mntobj.ObjectId; | |
| 1210 | raw->BpTotal = 0; | |
| 1211 | raw->BpComplete = 0; | |
| 1212 | fib->Header.Size += sizeof(struct aac_raw_io); | |
| 1213 | cm->cm_sgtable = (struct aac_sg_table *)&raw->SgMapRaw; | |
| 1214 | if (bp->b_cmd == BUF_CMD_READ) { | |
| 1215 | raw->Flags = 1; | |
| 1216 | cm->cm_flags |= AAC_CMD_DATAIN; | |
| 1217 | } else { | |
| 1218 | raw->Flags = 0; | |
| 1219 | cm->cm_flags |= AAC_CMD_DATAOUT; | |
| 1220 | } | |
| 1221 | } else if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) { | |
| 1222 | fib->Header.Command = ContainerCommand; | |
| 1223 | if (bp->b_cmd == BUF_CMD_READ) { | |
| 1224 | struct aac_blockread *br; | |
| 1225 | br = (struct aac_blockread *)&fib->data[0]; | |
| 1226 | br->Command = VM_CtBlockRead; | |
| 1227 | br->ContainerId = ad->ad_container->co_mntobj.ObjectId; | |
| 1228 | br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; | |
| 1229 | br->ByteCount = bp->b_bcount; | |
| 1230 | fib->Header.Size += sizeof(struct aac_blockread); | |
| 1231 | cm->cm_sgtable = &br->SgMap; | |
| 1232 | cm->cm_flags |= AAC_CMD_DATAIN; | |
| 1233 | } else { | |
| 1234 | struct aac_blockwrite *bw; | |
| 1235 | bw = (struct aac_blockwrite *)&fib->data[0]; | |
| 1236 | bw->Command = VM_CtBlockWrite; | |
| 1237 | bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; | |
| 1238 | bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; | |
| 1239 | bw->ByteCount = bp->b_bcount; | |
| 1240 | bw->Stable = CUNSTABLE; | |
| 1241 | fib->Header.Size += sizeof(struct aac_blockwrite); | |
| 1242 | cm->cm_flags |= AAC_CMD_DATAOUT; | |
| 1243 | cm->cm_sgtable = &bw->SgMap; | |
| 1244 | } | |
| 984263bc | 1245 | } else { |
| d9773475 PA |
1246 | fib->Header.Command = ContainerCommand64; |
| 1247 | if (bp->b_cmd == BUF_CMD_READ) { | |
| 1248 | struct aac_blockread64 *br; | |
| 1249 | br = (struct aac_blockread64 *)&fib->data[0]; | |
| 1250 | br->Command = VM_CtHostRead64; | |
| 1251 | br->ContainerId = ad->ad_container->co_mntobj.ObjectId; | |
| 1252 | br->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE; | |
| 1253 | br->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; | |
| 1254 | br->Pad = 0; | |
| 1255 | br->Flags = 0; | |
| 1256 | fib->Header.Size += sizeof(struct aac_blockread64); | |
| e9ae7f4f | 1257 | cm->cm_flags |= AAC_CMD_DATAIN; |
| d9773475 PA |
1258 | cm->cm_sgtable = (struct aac_sg_table *)&br->SgMap64; |
| 1259 | } else { | |
| 1260 | struct aac_blockwrite64 *bw; | |
| 1261 | bw = (struct aac_blockwrite64 *)&fib->data[0]; | |
| 1262 | bw->Command = VM_CtHostWrite64; | |
| 1263 | bw->ContainerId = ad->ad_container->co_mntobj.ObjectId; | |
| 1264 | bw->SectorCount = bp->b_bcount / AAC_BLOCK_SIZE; | |
| 1265 | bw->BlockNumber = bio->bio_offset / AAC_BLOCK_SIZE; | |
| 1266 | bw->Pad = 0; | |
| 1267 | bw->Flags = 0; | |
| 1268 | fib->Header.Size += sizeof(struct aac_blockwrite64); | |
| e9ae7f4f | 1269 | cm->cm_flags |= AAC_CMD_DATAOUT; |
| d9773475 PA |
1270 | cm->cm_sgtable = (struct aac_sg_table *)&bw->SgMap64; |
| 1271 | } | |
| 984263bc MD |
1272 | } |
| 1273 | ||
| 1274 | *cmp = cm; | |
| 1275 | return(0); | |
| 1276 | ||
| 1277 | fail: | |
| 81b5c339 MD |
1278 | if (bio != NULL) |
| 1279 | aac_enqueue_bio(sc, bio); | |
| 984263bc MD |
1280 | if (cm != NULL) |
| 1281 | aac_release_command(cm); | |
| 1282 | return(ENOMEM); | |
| 1283 | } | |
| 1284 | ||
| 1285 | /* | |
| 1286 | * Handle a bio-instigated command that has been completed. | |
| 1287 | */ | |
| 1288 | static void | |
| 1289 | aac_bio_complete(struct aac_command *cm) | |
| 1290 | { | |
| 1291 | struct aac_blockread_response *brr; | |
| 1292 | struct aac_blockwrite_response *bwr; | |
| 81b5c339 | 1293 | struct bio *bio; |
| 1eabbf32 | 1294 | struct buf *bp; |
| 81b5c339 | 1295 | const char *code; |
| 984263bc MD |
1296 | AAC_FSAStatus status; |
| 1297 | ||
| 1298 | /* fetch relevant status and then release the command */ | |
| 81b5c339 MD |
1299 | bio = (struct bio *)cm->cm_private; |
| 1300 | bp = bio->bio_buf; | |
| 10f3fee5 | 1301 | if (bp->b_cmd == BUF_CMD_READ) { |
| 984263bc MD |
1302 | brr = (struct aac_blockread_response *)&cm->cm_fib->data[0]; |
| 1303 | status = brr->Status; | |
| 1304 | } else { | |
| 1305 | bwr = (struct aac_blockwrite_response *)&cm->cm_fib->data[0]; | |
| 1306 | status = bwr->Status; | |
| 1307 | } | |
| 1308 | aac_release_command(cm); | |
| 1309 | ||
| 1310 | /* fix up the bio based on status */ | |
| 1311 | if (status == ST_OK) { | |
| 1eabbf32 | 1312 | bp->b_resid = 0; |
| 4090d6ff | 1313 | code = NULL; |
| 984263bc | 1314 | } else { |
| 1eabbf32 HP |
1315 | bp->b_error = EIO; |
| 1316 | bp->b_flags |= B_ERROR; | |
| 984263bc | 1317 | /* pass an error string out to the disk layer */ |
| 81b5c339 | 1318 | code = aac_describe_code(aac_command_status_table, status); |
| 984263bc | 1319 | } |
| 81b5c339 | 1320 | aac_biodone(bio, code); |
| 984263bc MD |
1321 | } |
| 1322 | ||
| 1323 | /* | |
| 984263bc MD |
1324 | * Submit a command to the controller, return when it completes. |
| 1325 | * XXX This is very dangerous! If the card has gone out to lunch, we could | |
| 1326 | * be stuck here forever. At the same time, signals are not caught | |
| d9773475 PA |
1327 | * because there is a risk that a signal could wakeup the sleep before |
| 1328 | * the card has a chance to complete the command. Since there is no way | |
| 1329 | * to cancel a command that is in progress, we can't protect against the | |
| 1330 | * card completing a command late and spamming the command and data | |
| 1331 | * memory. So, we are held hostage until the command completes. | |
| 984263bc MD |
1332 | */ |
| 1333 | static int | |
| d9773475 | 1334 | aac_wait_command(struct aac_command *cm) |
| 984263bc | 1335 | { |
| d9773475 PA |
1336 | struct aac_softc *sc; |
| 1337 | int error; | |
| 984263bc | 1338 | |
| d9773475 | 1339 | sc = cm->cm_sc; |
| e9ae7f4f | 1340 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 1341 | |
| 984263bc | 1342 | /* Put the command on the ready queue and get things going */ |
| 984263bc | 1343 | aac_enqueue_ready(cm); |
| d9773475 | 1344 | aac_startio(sc); |
| e9ae7f4f | 1345 | error = lksleep(cm, &sc->aac_io_lock, 0, "aacwait", 0); |
| 984263bc MD |
1346 | return(error); |
| 1347 | } | |
| 1348 | ||
| 1349 | /* | |
| 1350 | *Command Buffer Management | |
| 1351 | */ | |
| 1352 | ||
| 1353 | /* | |
| 1354 | * Allocate a command. | |
| 1355 | */ | |
| 1356 | int | |
| 1357 | aac_alloc_command(struct aac_softc *sc, struct aac_command **cmp) | |
| 1358 | { | |
| 1359 | struct aac_command *cm; | |
| 1360 | ||
| e9ae7f4f | 1361 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 1362 | |
| d9773475 PA |
1363 | if ((cm = aac_dequeue_free(sc)) == NULL) { |
| 1364 | if (sc->total_fibs < sc->aac_max_fibs) { | |
| 1365 | sc->aifflags |= AAC_AIFFLAGS_ALLOCFIBS; | |
| 1366 | wakeup(sc->aifthread); | |
| 1367 | } | |
| 1368 | return (EBUSY); | |
| 1369 | } | |
| 984263bc MD |
1370 | |
| 1371 | *cmp = cm; | |
| 1372 | return(0); | |
| 1373 | } | |
| 1374 | ||
| 1375 | /* | |
| 1376 | * Release a command back to the freelist. | |
| 1377 | */ | |
| 1378 | void | |
| 1379 | aac_release_command(struct aac_command *cm) | |
| 1380 | { | |
| d9773475 PA |
1381 | struct aac_event *event; |
| 1382 | struct aac_softc *sc; | |
| 1383 | ||
| e9ae7f4f SW |
1384 | sc = cm->cm_sc; |
| 1385 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 984263bc | 1386 | |
| e9ae7f4f | 1387 | /* (re)initialize the command/FIB */ |
| 984263bc MD |
1388 | cm->cm_sgtable = NULL; |
| 1389 | cm->cm_flags = 0; | |
| 1390 | cm->cm_complete = NULL; | |
| 1391 | cm->cm_private = NULL; | |
| e9ae7f4f | 1392 | cm->cm_queue = AAC_ADAP_NORM_CMD_QUEUE; |
| 984263bc MD |
1393 | cm->cm_fib->Header.XferState = AAC_FIBSTATE_EMPTY; |
| 1394 | cm->cm_fib->Header.StructType = AAC_FIBTYPE_TFIB; | |
| 1395 | cm->cm_fib->Header.Flags = 0; | |
| d9773475 | 1396 | cm->cm_fib->Header.SenderSize = cm->cm_sc->aac_max_fib_size; |
| 984263bc | 1397 | |
| d9773475 | 1398 | /* |
| 984263bc MD |
1399 | * These are duplicated in aac_start to cover the case where an |
| 1400 | * intermediate stage may have destroyed them. They're left | |
| e9ae7f4f | 1401 | * initialized here for debugging purposes only. |
| 984263bc | 1402 | */ |
| 984263bc MD |
1403 | cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; |
| 1404 | cm->cm_fib->Header.SenderData = 0; | |
| 1405 | ||
| 1406 | aac_enqueue_free(cm); | |
| d9773475 | 1407 | |
| e9ae7f4f SW |
1408 | /* |
| 1409 | * Dequeue all events so that there's no risk of events getting | |
| 1410 | * stranded. | |
| 1411 | */ | |
| 1412 | while ((event = TAILQ_FIRST(&sc->aac_ev_cmfree)) != NULL) { | |
| d9773475 PA |
1413 | TAILQ_REMOVE(&sc->aac_ev_cmfree, event, ev_links); |
| 1414 | event->ev_callback(sc, event, event->ev_arg); | |
| 1415 | } | |
| 984263bc MD |
1416 | } |
| 1417 | ||
| 1418 | /* | |
| 1419 | * Map helper for command/FIB allocation. | |
| 1420 | */ | |
| 1421 | static void | |
| 1422 | aac_map_command_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) | |
| 1423 | { | |
| d9773475 | 1424 | uint64_t *fibphys; |
| 984263bc | 1425 | |
| d9773475 | 1426 | fibphys = (uint64_t *)arg; |
| 984263bc | 1427 | |
| d9773475 | 1428 | *fibphys = segs[0].ds_addr; |
| 984263bc MD |
1429 | } |
| 1430 | ||
| 1431 | /* | |
| e9ae7f4f | 1432 | * Allocate and initialize commands/FIBs for this adapter. |
| 984263bc MD |
1433 | */ |
| 1434 | static int | |
| 1435 | aac_alloc_commands(struct aac_softc *sc) | |
| 1436 | { | |
| 1437 | struct aac_command *cm; | |
| d9773475 PA |
1438 | struct aac_fibmap *fm; |
| 1439 | uint64_t fibphys; | |
| 1440 | int i, error; | |
| 1441 | ||
| e9ae7f4f | 1442 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 PA |
1443 | |
| 1444 | if (sc->total_fibs + sc->aac_max_fibs_alloc > sc->aac_max_fibs) | |
| 1445 | return (ENOMEM); | |
| 1446 | ||
| 1447 | fm = kmalloc(sizeof(struct aac_fibmap), M_AACBUF, M_INTWAIT | M_ZERO); | |
| 984263bc MD |
1448 | |
| 1449 | /* allocate the FIBs in DMAable memory and load them */ | |
| d9773475 PA |
1450 | if (bus_dmamem_alloc(sc->aac_fib_dmat, (void **)&fm->aac_fibs, |
| 1451 | BUS_DMA_NOWAIT, &fm->aac_fibmap)) { | |
| 1452 | device_printf(sc->aac_dev, | |
| 1453 | "Not enough contiguous memory available.\n"); | |
| 1454 | kfree(fm, M_AACBUF); | |
| 1455 | return (ENOMEM); | |
| 984263bc MD |
1456 | } |
| 1457 | ||
| d9773475 | 1458 | /* Ignore errors since this doesn't bounce */ |
| e9ae7f4f SW |
1459 | (void)bus_dmamap_load(sc->aac_fib_dmat, fm->aac_fibmap, fm->aac_fibs, |
| 1460 | sc->aac_max_fibs_alloc * sc->aac_max_fib_size, | |
| 1461 | aac_map_command_helper, &fibphys, 0); | |
| 984263bc | 1462 | |
| e9ae7f4f | 1463 | /* initialize constant fields in the command structure */ |
| d9773475 PA |
1464 | bzero(fm->aac_fibs, sc->aac_max_fibs_alloc * sc->aac_max_fib_size); |
| 1465 | for (i = 0; i < sc->aac_max_fibs_alloc; i++) { | |
| 1466 | cm = sc->aac_commands + sc->total_fibs; | |
| 1467 | fm->aac_commands = cm; | |
| 984263bc | 1468 | cm->cm_sc = sc; |
| d9773475 PA |
1469 | cm->cm_fib = (struct aac_fib *) |
| 1470 | ((u_int8_t *)fm->aac_fibs + i*sc->aac_max_fib_size); | |
| 1471 | cm->cm_fibphys = fibphys + i*sc->aac_max_fib_size; | |
| 1472 | cm->cm_index = sc->total_fibs; | |
| 984263bc | 1473 | |
| d9773475 PA |
1474 | if ((error = bus_dmamap_create(sc->aac_buffer_dmat, 0, |
| 1475 | &cm->cm_datamap)) != 0) | |
| 1476 | break; | |
| e9ae7f4f | 1477 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 PA |
1478 | aac_release_command(cm); |
| 1479 | sc->total_fibs++; | |
| e9ae7f4f | 1480 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc | 1481 | } |
| d9773475 PA |
1482 | |
| 1483 | if (i > 0) { | |
| e9ae7f4f | 1484 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 | 1485 | TAILQ_INSERT_TAIL(&sc->aac_fibmap_tqh, fm, fm_link); |
| e9ae7f4f SW |
1486 | fwprintf(sc, HBA_FLAGS_DBG_COMM_B, "total_fibs= %d\n", sc->total_fibs); |
| 1487 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| d9773475 PA |
1488 | return (0); |
| 1489 | } | |
| 1490 | ||
| 1491 | bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); | |
| 1492 | bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); | |
| 1493 | kfree(fm, M_AACBUF); | |
| 1494 | return (ENOMEM); | |
| 984263bc MD |
1495 | } |
| 1496 | ||
| 1497 | /* | |
| 1498 | * Free FIBs owned by this adapter. | |
| 1499 | */ | |
| 1500 | static void | |
| 1501 | aac_free_commands(struct aac_softc *sc) | |
| 1502 | { | |
| d9773475 PA |
1503 | struct aac_fibmap *fm; |
| 1504 | struct aac_command *cm; | |
| 984263bc MD |
1505 | int i; |
| 1506 | ||
| e9ae7f4f | 1507 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 1508 | |
| d9773475 | 1509 | while ((fm = TAILQ_FIRST(&sc->aac_fibmap_tqh)) != NULL) { |
| 984263bc | 1510 | |
| d9773475 PA |
1511 | TAILQ_REMOVE(&sc->aac_fibmap_tqh, fm, fm_link); |
| 1512 | /* | |
| 1513 | * We check against total_fibs to handle partially | |
| 1514 | * allocated blocks. | |
| 1515 | */ | |
| 1516 | for (i = 0; i < sc->aac_max_fibs_alloc && sc->total_fibs--; i++) { | |
| 1517 | cm = fm->aac_commands + i; | |
| 1518 | bus_dmamap_destroy(sc->aac_buffer_dmat, cm->cm_datamap); | |
| 1519 | } | |
| 1520 | bus_dmamap_unload(sc->aac_fib_dmat, fm->aac_fibmap); | |
| 1521 | bus_dmamem_free(sc->aac_fib_dmat, fm->aac_fibs, fm->aac_fibmap); | |
| 1522 | kfree(fm, M_AACBUF); | |
| 1523 | } | |
| 984263bc MD |
1524 | } |
| 1525 | ||
| 1526 | /* | |
| 1527 | * Command-mapping helper function - populate this command's s/g table. | |
| 1528 | */ | |
| 1529 | static void | |
| 1530 | aac_map_command_sg(void *arg, bus_dma_segment_t *segs, int nseg, int error) | |
| 1531 | { | |
| d9773475 | 1532 | struct aac_softc *sc; |
| 984263bc MD |
1533 | struct aac_command *cm; |
| 1534 | struct aac_fib *fib; | |
| 984263bc MD |
1535 | int i; |
| 1536 | ||
| 984263bc | 1537 | cm = (struct aac_command *)arg; |
| d9773475 | 1538 | sc = cm->cm_sc; |
| 984263bc | 1539 | fib = cm->cm_fib; |
| e9ae7f4f | 1540 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 1541 | |
| 984263bc | 1542 | /* copy into the FIB */ |
| d9773475 PA |
1543 | if (cm->cm_sgtable != NULL) { |
| 1544 | if (fib->Header.Command == RawIo) { | |
| 1545 | struct aac_sg_tableraw *sg; | |
| 1546 | sg = (struct aac_sg_tableraw *)cm->cm_sgtable; | |
| 1547 | sg->SgCount = nseg; | |
| 1548 | for (i = 0; i < nseg; i++) { | |
| 1549 | sg->SgEntryRaw[i].SgAddress = segs[i].ds_addr; | |
| 1550 | sg->SgEntryRaw[i].SgByteCount = segs[i].ds_len; | |
| 1551 | sg->SgEntryRaw[i].Next = 0; | |
| 1552 | sg->SgEntryRaw[i].Prev = 0; | |
| 1553 | sg->SgEntryRaw[i].Flags = 0; | |
| 1554 | } | |
| 1555 | /* update the FIB size for the s/g count */ | |
| 1556 | fib->Header.Size += nseg*sizeof(struct aac_sg_entryraw); | |
| 1557 | } else if ((cm->cm_sc->flags & AAC_FLAGS_SG_64BIT) == 0) { | |
| 1558 | struct aac_sg_table *sg; | |
| 1559 | sg = cm->cm_sgtable; | |
| 1560 | sg->SgCount = nseg; | |
| 1561 | for (i = 0; i < nseg; i++) { | |
| 1562 | sg->SgEntry[i].SgAddress = segs[i].ds_addr; | |
| 1563 | sg->SgEntry[i].SgByteCount = segs[i].ds_len; | |
| 1564 | } | |
| 1565 | /* update the FIB size for the s/g count */ | |
| 1566 | fib->Header.Size += nseg*sizeof(struct aac_sg_entry); | |
| 1567 | } else { | |
| 1568 | struct aac_sg_table64 *sg; | |
| 1569 | sg = (struct aac_sg_table64 *)cm->cm_sgtable; | |
| 1570 | sg->SgCount = nseg; | |
| 1571 | for (i = 0; i < nseg; i++) { | |
| 1572 | sg->SgEntry64[i].SgAddress = segs[i].ds_addr; | |
| 1573 | sg->SgEntry64[i].SgByteCount = segs[i].ds_len; | |
| 1574 | } | |
| 1575 | /* update the FIB size for the s/g count */ | |
| 1576 | fib->Header.Size += nseg*sizeof(struct aac_sg_entry64); | |
| 1577 | } | |
| 1578 | } | |
| 984263bc | 1579 | |
| d9773475 PA |
1580 | /* Fix up the address values in the FIB. Use the command array index |
| 1581 | * instead of a pointer since these fields are only 32 bits. Shift | |
| 1582 | * the SenderFibAddress over to make room for the fast response bit | |
| 1583 | * and for the AIF bit | |
| 1584 | */ | |
| 1585 | cm->cm_fib->Header.SenderFibAddress = (cm->cm_index << 2); | |
| 1586 | cm->cm_fib->Header.ReceiverFibAddress = (u_int32_t)cm->cm_fibphys; | |
| 984263bc | 1587 | |
| d9773475 PA |
1588 | /* save a pointer to the command for speedy reverse-lookup */ |
| 1589 | cm->cm_fib->Header.SenderData = cm->cm_index; | |
| 1590 | ||
| 1591 | if (cm->cm_flags & AAC_CMD_DATAIN) | |
| 1592 | bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, | |
| 1593 | BUS_DMASYNC_PREREAD); | |
| 1594 | if (cm->cm_flags & AAC_CMD_DATAOUT) | |
| 1595 | bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, | |
| 1596 | BUS_DMASYNC_PREWRITE); | |
| 1597 | cm->cm_flags |= AAC_CMD_MAPPED; | |
| 984263bc | 1598 | |
| d9773475 PA |
1599 | if (sc->flags & AAC_FLAGS_NEW_COMM) { |
| 1600 | int count = 10000000L; | |
| 1601 | while (AAC_SEND_COMMAND(sc, cm) != 0) { | |
| 1602 | if (--count == 0) { | |
| 1603 | aac_unmap_command(cm); | |
| 1604 | sc->flags |= AAC_QUEUE_FRZN; | |
| 1605 | aac_requeue_ready(cm); | |
| 1606 | } | |
| 1607 | DELAY(5); /* wait 5 usec. */ | |
| 1608 | } | |
| 1609 | } else { | |
| 1610 | /* Put the FIB on the outbound queue */ | |
| 1611 | if (aac_enqueue_fib(sc, cm->cm_queue, cm) == EBUSY) { | |
| 1612 | aac_unmap_command(cm); | |
| 1613 | sc->flags |= AAC_QUEUE_FRZN; | |
| 1614 | aac_requeue_ready(cm); | |
| 1615 | } | |
| 984263bc | 1616 | } |
| e9ae7f4f SW |
1617 | |
| 1618 | return; | |
| 984263bc MD |
1619 | } |
| 1620 | ||
| 1621 | /* | |
| 1622 | * Unmap a command from controller-visible space. | |
| 1623 | */ | |
| 1624 | static void | |
| 1625 | aac_unmap_command(struct aac_command *cm) | |
| 1626 | { | |
| 1627 | struct aac_softc *sc; | |
| 1628 | ||
| 984263bc | 1629 | sc = cm->cm_sc; |
| e9ae7f4f | 1630 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
1631 | |
| 1632 | if (!(cm->cm_flags & AAC_CMD_MAPPED)) | |
| 1633 | return; | |
| 1634 | ||
| 1635 | if (cm->cm_datalen != 0) { | |
| 1636 | if (cm->cm_flags & AAC_CMD_DATAIN) | |
| 1637 | bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, | |
| 1638 | BUS_DMASYNC_POSTREAD); | |
| 1639 | if (cm->cm_flags & AAC_CMD_DATAOUT) | |
| 1640 | bus_dmamap_sync(sc->aac_buffer_dmat, cm->cm_datamap, | |
| 1641 | BUS_DMASYNC_POSTWRITE); | |
| 1642 | ||
| 1643 | bus_dmamap_unload(sc->aac_buffer_dmat, cm->cm_datamap); | |
| 1644 | } | |
| 1645 | cm->cm_flags &= ~AAC_CMD_MAPPED; | |
| 1646 | } | |
| 1647 | ||
| 1648 | /* | |
| 1649 | * Hardware Interface | |
| 1650 | */ | |
| 1651 | ||
| 1652 | /* | |
| e9ae7f4f | 1653 | * Initialize the adapter. |
| 984263bc MD |
1654 | */ |
| 1655 | static void | |
| 1656 | aac_common_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) | |
| 1657 | { | |
| 1658 | struct aac_softc *sc; | |
| 1659 | ||
| 984263bc | 1660 | sc = (struct aac_softc *)arg; |
| e9ae7f4f | 1661 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
1662 | |
| 1663 | sc->aac_common_busaddr = segs[0].ds_addr; | |
| 1664 | } | |
| 1665 | ||
| 1666 | static int | |
| 1667 | aac_check_firmware(struct aac_softc *sc) | |
| 1668 | { | |
| e9ae7f4f | 1669 | u_int32_t code, major, minor, options = 0, atu_size = 0; |
| d9773475 | 1670 | int status; |
| e9ae7f4f | 1671 | time_t then; |
| 984263bc | 1672 | |
| e9ae7f4f SW |
1673 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 1674 | /* | |
| 1675 | * Wait for the adapter to come ready. | |
| 1676 | */ | |
| 1677 | then = time_second; | |
| 1678 | do { | |
| 1679 | code = AAC_GET_FWSTATUS(sc); | |
| 1680 | if (code & AAC_SELF_TEST_FAILED) { | |
| 1681 | device_printf(sc->aac_dev, "FATAL: selftest failed\n"); | |
| 1682 | return(ENXIO); | |
| 1683 | } | |
| 1684 | if (code & AAC_KERNEL_PANIC) { | |
| 1685 | device_printf(sc->aac_dev, | |
| 1686 | "FATAL: controller kernel panic"); | |
| 1687 | return(ENXIO); | |
| 1688 | } | |
| 1689 | if (time_second > (then + AAC_BOOT_TIMEOUT)) { | |
| 1690 | device_printf(sc->aac_dev, | |
| 1691 | "FATAL: controller not coming ready, " | |
| 1692 | "status %x\n", code); | |
| 1693 | return(ENXIO); | |
| 1694 | } | |
| 1695 | } while (!(code & AAC_UP_AND_RUNNING)); | |
| 984263bc MD |
1696 | |
| 1697 | /* | |
| 1698 | * Retrieve the firmware version numbers. Dell PERC2/QC cards with | |
| 1699 | * firmware version 1.x are not compatible with this driver. | |
| 1700 | */ | |
| 1701 | if (sc->flags & AAC_FLAGS_PERC2QC) { | |
| 1702 | if (aac_sync_command(sc, AAC_MONKER_GETKERNVER, 0, 0, 0, 0, | |
| 1703 | NULL)) { | |
| 1704 | device_printf(sc->aac_dev, | |
| 1705 | "Error reading firmware version\n"); | |
| 1706 | return (EIO); | |
| 1707 | } | |
| 1708 | ||
| 1709 | /* These numbers are stored as ASCII! */ | |
| 1710 | major = (AAC_GET_MAILBOX(sc, 1) & 0xff) - 0x30; | |
| 1711 | minor = (AAC_GET_MAILBOX(sc, 2) & 0xff) - 0x30; | |
| 1712 | if (major == 1) { | |
| 1713 | device_printf(sc->aac_dev, | |
| 1714 | "Firmware version %d.%d is not supported.\n", | |
| 1715 | major, minor); | |
| 1716 | return (EINVAL); | |
| 1717 | } | |
| 1718 | } | |
| 1719 | ||
| 1720 | /* | |
| 1721 | * Retrieve the capabilities/supported options word so we know what | |
| d9773475 PA |
1722 | * work-arounds to enable. Some firmware revs don't support this |
| 1723 | * command. | |
| 984263bc | 1724 | */ |
| d9773475 PA |
1725 | if (aac_sync_command(sc, AAC_MONKER_GETINFO, 0, 0, 0, 0, &status)) { |
| 1726 | if (status != AAC_SRB_STS_INVALID_REQUEST) { | |
| 1727 | device_printf(sc->aac_dev, | |
| 1728 | "RequestAdapterInfo failed\n"); | |
| 1729 | return (EIO); | |
| 1730 | } | |
| 1731 | } else { | |
| 1732 | options = AAC_GET_MAILBOX(sc, 1); | |
| 1733 | atu_size = AAC_GET_MAILBOX(sc, 2); | |
| 1734 | sc->supported_options = options; | |
| 1735 | ||
| 1736 | if ((options & AAC_SUPPORTED_4GB_WINDOW) != 0 && | |
| 1737 | (sc->flags & AAC_FLAGS_NO4GB) == 0) | |
| 1738 | sc->flags |= AAC_FLAGS_4GB_WINDOW; | |
| 1739 | if (options & AAC_SUPPORTED_NONDASD) | |
| 1740 | sc->flags |= AAC_FLAGS_ENABLE_CAM; | |
| 1741 | if ((options & AAC_SUPPORTED_SGMAP_HOST64) != 0 | |
| 1742 | && (sizeof(bus_addr_t) > 4)) { | |
| 1743 | device_printf(sc->aac_dev, | |
| 1744 | "Enabling 64-bit address support\n"); | |
| 1745 | sc->flags |= AAC_FLAGS_SG_64BIT; | |
| 1746 | } | |
| 1747 | if ((options & AAC_SUPPORTED_NEW_COMM) | |
| 1748 | && sc->aac_if.aif_send_command) | |
| 1749 | sc->flags |= AAC_FLAGS_NEW_COMM; | |
| 1750 | if (options & AAC_SUPPORTED_64BIT_ARRAYSIZE) | |
| 1751 | sc->flags |= AAC_FLAGS_ARRAY_64BIT; | |
| 1752 | } | |
| 1753 | ||
| 1754 | /* Check for broken hardware that does a lower number of commands */ | |
| 1755 | sc->aac_max_fibs = (sc->flags & AAC_FLAGS_256FIBS ? 256:512); | |
| 1756 | ||
| 1757 | /* Remap mem. resource, if required */ | |
| 1758 | if ((sc->flags & AAC_FLAGS_NEW_COMM) && | |
| e9ae7f4f | 1759 | atu_size > rman_get_size(sc->aac_regs_res1)) { |
| d9773475 PA |
1760 | bus_release_resource( |
| 1761 | sc->aac_dev, SYS_RES_MEMORY, | |
| e9ae7f4f SW |
1762 | sc->aac_regs_rid1, sc->aac_regs_res1); |
| 1763 | sc->aac_regs_res1 = bus_alloc_resource( | |
| 1764 | sc->aac_dev, SYS_RES_MEMORY, &sc->aac_regs_rid1, | |
| d9773475 | 1765 | 0ul, ~0ul, atu_size, RF_ACTIVE); |
| e9ae7f4f SW |
1766 | if (sc->aac_regs_res1 == NULL) { |
| 1767 | sc->aac_regs_res1 = bus_alloc_resource_any( | |
| d9773475 | 1768 | sc->aac_dev, SYS_RES_MEMORY, |
| e9ae7f4f SW |
1769 | &sc->aac_regs_rid1, RF_ACTIVE); |
| 1770 | if (sc->aac_regs_res1 == NULL) { | |
| d9773475 PA |
1771 | device_printf(sc->aac_dev, |
| 1772 | "couldn't allocate register window\n"); | |
| 1773 | return (ENXIO); | |
| 1774 | } | |
| 1775 | sc->flags &= ~AAC_FLAGS_NEW_COMM; | |
| 1776 | } | |
| e9ae7f4f SW |
1777 | sc->aac_btag1 = rman_get_bustag(sc->aac_regs_res1); |
| 1778 | sc->aac_bhandle1 = rman_get_bushandle(sc->aac_regs_res1); | |
| 1779 | ||
| 1780 | if (sc->aac_hwif == AAC_HWIF_NARK) { | |
| 1781 | sc->aac_regs_res0 = sc->aac_regs_res1; | |
| 1782 | sc->aac_regs_rid0 = sc->aac_regs_rid1; | |
| 1783 | sc->aac_btag0 = sc->aac_btag1; | |
| 1784 | sc->aac_bhandle0 = sc->aac_bhandle1; | |
| 1785 | } | |
| 984263bc | 1786 | } |
| 984263bc | 1787 | |
| d9773475 PA |
1788 | /* Read preferred settings */ |
| 1789 | sc->aac_max_fib_size = sizeof(struct aac_fib); | |
| 1790 | sc->aac_max_sectors = 128; /* 64KB */ | |
| 1791 | if (sc->flags & AAC_FLAGS_SG_64BIT) | |
| 1792 | sc->aac_sg_tablesize = (AAC_FIB_DATASIZE | |
| e9ae7f4f SW |
1793 | - sizeof(struct aac_blockwrite64)) |
| 1794 | / sizeof(struct aac_sg_entry64); | |
| d9773475 PA |
1795 | else |
| 1796 | sc->aac_sg_tablesize = (AAC_FIB_DATASIZE | |
| e9ae7f4f SW |
1797 | - sizeof(struct aac_blockwrite)) |
| 1798 | / sizeof(struct aac_sg_entry); | |
| d9773475 PA |
1799 | |
| 1800 | if (!aac_sync_command(sc, AAC_MONKER_GETCOMMPREF, 0, 0, 0, 0, NULL)) { | |
| 1801 | options = AAC_GET_MAILBOX(sc, 1); | |
| 1802 | sc->aac_max_fib_size = (options & 0xFFFF); | |
| 1803 | sc->aac_max_sectors = (options >> 16) << 1; | |
| 1804 | options = AAC_GET_MAILBOX(sc, 2); | |
| 1805 | sc->aac_sg_tablesize = (options >> 16); | |
| 1806 | options = AAC_GET_MAILBOX(sc, 3); | |
| 1807 | sc->aac_max_fibs = (options & 0xFFFF); | |
| 1808 | } | |
| 1809 | if (sc->aac_max_fib_size > PAGE_SIZE) | |
| 1810 | sc->aac_max_fib_size = PAGE_SIZE; | |
| 1811 | sc->aac_max_fibs_alloc = PAGE_SIZE / sc->aac_max_fib_size; | |
| 984263bc | 1812 | |
| e9ae7f4f SW |
1813 | if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { |
| 1814 | sc->flags |= AAC_FLAGS_RAW_IO; | |
| 1815 | device_printf(sc->aac_dev, "Enable Raw I/O\n"); | |
| 1816 | } | |
| 1817 | if ((sc->flags & AAC_FLAGS_RAW_IO) && | |
| 1818 | (sc->flags & AAC_FLAGS_ARRAY_64BIT)) { | |
| 1819 | sc->flags |= AAC_FLAGS_LBA_64BIT; | |
| 1820 | device_printf(sc->aac_dev, "Enable 64-bit array\n"); | |
| 1821 | } | |
| 1822 | ||
| 984263bc MD |
1823 | return (0); |
| 1824 | } | |
| 1825 | ||
| 1826 | static int | |
| 1827 | aac_init(struct aac_softc *sc) | |
| 1828 | { | |
| 1829 | struct aac_adapter_init *ip; | |
| e9ae7f4f | 1830 | u_int32_t qoffset; |
| 984263bc MD |
1831 | int error; |
| 1832 | ||
| e9ae7f4f | 1833 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
1834 | |
| 1835 | /* | |
| 1836 | * Fill in the init structure. This tells the adapter about the | |
| 1837 | * physical location of various important shared data structures. | |
| 1838 | */ | |
| 1839 | ip = &sc->aac_common->ac_init; | |
| 1840 | ip->InitStructRevision = AAC_INIT_STRUCT_REVISION; | |
| d9773475 PA |
1841 | if (sc->aac_max_fib_size > sizeof(struct aac_fib)) { |
| 1842 | ip->InitStructRevision = AAC_INIT_STRUCT_REVISION_4; | |
| 1843 | sc->flags |= AAC_FLAGS_RAW_IO; | |
| 1844 | } | |
| 984263bc MD |
1845 | ip->MiniPortRevision = AAC_INIT_STRUCT_MINIPORT_REVISION; |
| 1846 | ||
| 1847 | ip->AdapterFibsPhysicalAddress = sc->aac_common_busaddr + | |
| 1848 | offsetof(struct aac_common, ac_fibs); | |
| d9773475 | 1849 | ip->AdapterFibsVirtualAddress = 0; |
| 984263bc MD |
1850 | ip->AdapterFibsSize = AAC_ADAPTER_FIBS * sizeof(struct aac_fib); |
| 1851 | ip->AdapterFibAlign = sizeof(struct aac_fib); | |
| 1852 | ||
| 1853 | ip->PrintfBufferAddress = sc->aac_common_busaddr + | |
| 1854 | offsetof(struct aac_common, ac_printf); | |
| 1855 | ip->PrintfBufferSize = AAC_PRINTF_BUFSIZE; | |
| 1856 | ||
| d9773475 PA |
1857 | /* |
| 1858 | * The adapter assumes that pages are 4K in size, except on some | |
| 1859 | * broken firmware versions that do the page->byte conversion twice, | |
| 1860 | * therefore 'assuming' that this value is in 16MB units (2^24). | |
| 1861 | * Round up since the granularity is so high. | |
| 1862 | */ | |
| e9ae7f4f | 1863 | ip->HostPhysMemPages = ctob(physmem) / AAC_PAGE_SIZE; |
| d9773475 PA |
1864 | if (sc->flags & AAC_FLAGS_BROKEN_MEMMAP) { |
| 1865 | ip->HostPhysMemPages = | |
| 1866 | (ip->HostPhysMemPages + AAC_PAGE_SIZE) / AAC_PAGE_SIZE; | |
| 1867 | } | |
| 984263bc MD |
1868 | ip->HostElapsedSeconds = time_second; /* reset later if invalid */ |
| 1869 | ||
| d9773475 PA |
1870 | ip->InitFlags = 0; |
| 1871 | if (sc->flags & AAC_FLAGS_NEW_COMM) { | |
| e9ae7f4f | 1872 | ip->InitFlags |= AAC_INITFLAGS_NEW_COMM_SUPPORTED; |
| d9773475 PA |
1873 | device_printf(sc->aac_dev, "New comm. interface enabled\n"); |
| 1874 | } | |
| 1875 | ||
| 1876 | ip->MaxIoCommands = sc->aac_max_fibs; | |
| 1877 | ip->MaxIoSize = sc->aac_max_sectors << 9; | |
| 1878 | ip->MaxFibSize = sc->aac_max_fib_size; | |
| 1879 | ||
| 984263bc | 1880 | /* |
| e9ae7f4f | 1881 | * Initialize FIB queues. Note that it appears that the layout of the |
| 984263bc MD |
1882 | * indexes and the segmentation of the entries may be mandated by the |
| 1883 | * adapter, which is only told about the base of the queue index fields. | |
| 1884 | * | |
| 1885 | * The initial values of the indices are assumed to inform the adapter | |
| d9773475 | 1886 | * of the sizes of the respective queues, and theoretically it could |
| 984263bc MD |
1887 | * work out the entire layout of the queue structures from this. We |
| 1888 | * take the easy route and just lay this area out like everyone else | |
| 1889 | * does. | |
| 1890 | * | |
| d9773475 PA |
1891 | * The Linux driver uses a much more complex scheme whereby several |
| 1892 | * header records are kept for each queue. We use a couple of generic | |
| 984263bc MD |
1893 | * list manipulation functions which 'know' the size of each list by |
| 1894 | * virtue of a table. | |
| 1895 | */ | |
| d9773475 PA |
1896 | qoffset = offsetof(struct aac_common, ac_qbuf) + AAC_QUEUE_ALIGN; |
| 1897 | qoffset &= ~(AAC_QUEUE_ALIGN - 1); | |
| 1898 | sc->aac_queues = | |
| 1899 | (struct aac_queue_table *)((uintptr_t)sc->aac_common + qoffset); | |
| 1900 | ip->CommHeaderAddress = sc->aac_common_busaddr + qoffset; | |
| 984263bc MD |
1901 | |
| 1902 | sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = | |
| 1903 | AAC_HOST_NORM_CMD_ENTRIES; | |
| 1904 | sc->aac_queues->qt_qindex[AAC_HOST_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = | |
| 1905 | AAC_HOST_NORM_CMD_ENTRIES; | |
| 1906 | sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = | |
| 1907 | AAC_HOST_HIGH_CMD_ENTRIES; | |
| 1908 | sc->aac_queues->qt_qindex[AAC_HOST_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = | |
| 1909 | AAC_HOST_HIGH_CMD_ENTRIES; | |
| 1910 | sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_PRODUCER_INDEX] = | |
| 1911 | AAC_ADAP_NORM_CMD_ENTRIES; | |
| 1912 | sc->aac_queues->qt_qindex[AAC_ADAP_NORM_CMD_QUEUE][AAC_CONSUMER_INDEX] = | |
| 1913 | AAC_ADAP_NORM_CMD_ENTRIES; | |
| 1914 | sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_PRODUCER_INDEX] = | |
| 1915 | AAC_ADAP_HIGH_CMD_ENTRIES; | |
| 1916 | sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_CMD_QUEUE][AAC_CONSUMER_INDEX] = | |
| 1917 | AAC_ADAP_HIGH_CMD_ENTRIES; | |
| 1918 | sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= | |
| 1919 | AAC_HOST_NORM_RESP_ENTRIES; | |
| 1920 | sc->aac_queues->qt_qindex[AAC_HOST_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= | |
| 1921 | AAC_HOST_NORM_RESP_ENTRIES; | |
| 1922 | sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= | |
| 1923 | AAC_HOST_HIGH_RESP_ENTRIES; | |
| 1924 | sc->aac_queues->qt_qindex[AAC_HOST_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= | |
| 1925 | AAC_HOST_HIGH_RESP_ENTRIES; | |
| 1926 | sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_PRODUCER_INDEX]= | |
| 1927 | AAC_ADAP_NORM_RESP_ENTRIES; | |
| 1928 | sc->aac_queues->qt_qindex[AAC_ADAP_NORM_RESP_QUEUE][AAC_CONSUMER_INDEX]= | |
| 1929 | AAC_ADAP_NORM_RESP_ENTRIES; | |
| 1930 | sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_PRODUCER_INDEX]= | |
| 1931 | AAC_ADAP_HIGH_RESP_ENTRIES; | |
| 1932 | sc->aac_queues->qt_qindex[AAC_ADAP_HIGH_RESP_QUEUE][AAC_CONSUMER_INDEX]= | |
| 1933 | AAC_ADAP_HIGH_RESP_ENTRIES; | |
| 1934 | sc->aac_qentries[AAC_HOST_NORM_CMD_QUEUE] = | |
| 1935 | &sc->aac_queues->qt_HostNormCmdQueue[0]; | |
| 1936 | sc->aac_qentries[AAC_HOST_HIGH_CMD_QUEUE] = | |
| 1937 | &sc->aac_queues->qt_HostHighCmdQueue[0]; | |
| 1938 | sc->aac_qentries[AAC_ADAP_NORM_CMD_QUEUE] = | |
| 1939 | &sc->aac_queues->qt_AdapNormCmdQueue[0]; | |
| 1940 | sc->aac_qentries[AAC_ADAP_HIGH_CMD_QUEUE] = | |
| 1941 | &sc->aac_queues->qt_AdapHighCmdQueue[0]; | |
| 1942 | sc->aac_qentries[AAC_HOST_NORM_RESP_QUEUE] = | |
| 1943 | &sc->aac_queues->qt_HostNormRespQueue[0]; | |
| 1944 | sc->aac_qentries[AAC_HOST_HIGH_RESP_QUEUE] = | |
| 1945 | &sc->aac_queues->qt_HostHighRespQueue[0]; | |
| 1946 | sc->aac_qentries[AAC_ADAP_NORM_RESP_QUEUE] = | |
| 1947 | &sc->aac_queues->qt_AdapNormRespQueue[0]; | |
| 1948 | sc->aac_qentries[AAC_ADAP_HIGH_RESP_QUEUE] = | |
| 1949 | &sc->aac_queues->qt_AdapHighRespQueue[0]; | |
| 1950 | ||
| 1951 | /* | |
| 1952 | * Do controller-type-specific initialisation | |
| 1953 | */ | |
| 1954 | switch (sc->aac_hwif) { | |
| 1955 | case AAC_HWIF_I960RX: | |
| e9ae7f4f | 1956 | AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, ~0); |
| 984263bc | 1957 | break; |
| d9773475 | 1958 | case AAC_HWIF_RKT: |
| e9ae7f4f | 1959 | AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, ~0); |
| d9773475 PA |
1960 | break; |
| 1961 | default: | |
| 1962 | break; | |
| 984263bc MD |
1963 | } |
| 1964 | ||
| 1965 | /* | |
| 1966 | * Give the init structure to the controller. | |
| 1967 | */ | |
| d9773475 | 1968 | if (aac_sync_command(sc, AAC_MONKER_INITSTRUCT, |
| 984263bc MD |
1969 | sc->aac_common_busaddr + |
| 1970 | offsetof(struct aac_common, ac_init), 0, 0, 0, | |
| 1971 | NULL)) { | |
| 1972 | device_printf(sc->aac_dev, | |
| 1973 | "error establishing init structure\n"); | |
| 1974 | error = EIO; | |
| 1975 | goto out; | |
| 1976 | } | |
| 1977 | ||
| 1978 | error = 0; | |
| 1979 | out: | |
| 1980 | return(error); | |
| 1981 | } | |
| 1982 | ||
| e9ae7f4f SW |
1983 | static int |
| 1984 | aac_setup_intr(struct aac_softc *sc) | |
| 1985 | { | |
| 1986 | sc->aac_irq_rid = 0; | |
| 1987 | if ((sc->aac_irq = bus_alloc_resource_any(sc->aac_dev, SYS_RES_IRQ, | |
| 1988 | &sc->aac_irq_rid, | |
| 1989 | RF_SHAREABLE | | |
| 1990 | RF_ACTIVE)) == NULL) { | |
| 1991 | device_printf(sc->aac_dev, "can't allocate interrupt\n"); | |
| 1992 | return (EINVAL); | |
| 1993 | } | |
| 1994 | if (sc->flags & AAC_FLAGS_NEW_COMM) { | |
| 1995 | if (bus_setup_intr(sc->aac_dev, sc->aac_irq, | |
| 1996 | INTR_MPSAFE, | |
| 1997 | aac_new_intr, sc, &sc->aac_intr, NULL)) { | |
| 1998 | device_printf(sc->aac_dev, "can't set up interrupt\n"); | |
| 1999 | return (EINVAL); | |
| 2000 | } | |
| 2001 | } else { | |
| 2002 | if (bus_setup_intr(sc->aac_dev, sc->aac_irq, | |
| 2003 | 0, aac_filter, | |
| 2004 | sc, &sc->aac_intr, NULL)) { | |
| 2005 | device_printf(sc->aac_dev, | |
| 2006 | "can't set up interrupt filter\n"); | |
| 2007 | return (EINVAL); | |
| 2008 | } | |
| 2009 | } | |
| 2010 | return (0); | |
| 2011 | } | |
| 2012 | ||
| 984263bc MD |
2013 | /* |
| 2014 | * Send a synchronous command to the controller and wait for a result. | |
| d9773475 | 2015 | * Indicate if the controller completed the command with an error status. |
| 984263bc MD |
2016 | */ |
| 2017 | static int | |
| 2018 | aac_sync_command(struct aac_softc *sc, u_int32_t command, | |
| 2019 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3, | |
| 2020 | u_int32_t *sp) | |
| 2021 | { | |
| 2022 | time_t then; | |
| 2023 | u_int32_t status; | |
| 2024 | ||
| e9ae7f4f | 2025 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
2026 | |
| 2027 | /* populate the mailbox */ | |
| 2028 | AAC_SET_MAILBOX(sc, command, arg0, arg1, arg2, arg3); | |
| 2029 | ||
| 2030 | /* ensure the sync command doorbell flag is cleared */ | |
| 2031 | AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); | |
| 2032 | ||
| 2033 | /* then set it to signal the adapter */ | |
| 2034 | AAC_QNOTIFY(sc, AAC_DB_SYNC_COMMAND); | |
| 2035 | ||
| 2036 | /* spin waiting for the command to complete */ | |
| 2037 | then = time_second; | |
| 2038 | do { | |
| 2039 | if (time_second > (then + AAC_IMMEDIATE_TIMEOUT)) { | |
| e9ae7f4f | 2040 | fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "timed out"); |
| 984263bc MD |
2041 | return(EIO); |
| 2042 | } | |
| 2043 | } while (!(AAC_GET_ISTATUS(sc) & AAC_DB_SYNC_COMMAND)); | |
| 2044 | ||
| 2045 | /* clear the completion flag */ | |
| 2046 | AAC_CLEAR_ISTATUS(sc, AAC_DB_SYNC_COMMAND); | |
| 2047 | ||
| 2048 | /* get the command status */ | |
| 2049 | status = AAC_GET_MAILBOX(sc, 0); | |
| 2050 | if (sp != NULL) | |
| 2051 | *sp = status; | |
| 984263bc | 2052 | |
| d9773475 PA |
2053 | if (status != AAC_SRB_STS_SUCCESS) |
| 2054 | return (-1); | |
| 2055 | return(0); | |
| 984263bc MD |
2056 | } |
| 2057 | ||
| 984263bc | 2058 | int |
| d9773475 | 2059 | aac_sync_fib(struct aac_softc *sc, u_int32_t command, u_int32_t xferstate, |
| 984263bc MD |
2060 | struct aac_fib *fib, u_int16_t datasize) |
| 2061 | { | |
| e9ae7f4f SW |
2062 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 2063 | #if 0 /* XXX swildner */ | |
| d9773475 | 2064 | KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); |
| e9ae7f4f | 2065 | #endif |
| 984263bc MD |
2066 | |
| 2067 | if (datasize > AAC_FIB_DATASIZE) | |
| 2068 | return(EINVAL); | |
| 2069 | ||
| 2070 | /* | |
| 2071 | * Set up the sync FIB | |
| 2072 | */ | |
| 2073 | fib->Header.XferState = AAC_FIBSTATE_HOSTOWNED | | |
| 2074 | AAC_FIBSTATE_INITIALISED | | |
| 2075 | AAC_FIBSTATE_EMPTY; | |
| 2076 | fib->Header.XferState |= xferstate; | |
| 2077 | fib->Header.Command = command; | |
| 2078 | fib->Header.StructType = AAC_FIBTYPE_TFIB; | |
| e9ae7f4f | 2079 | fib->Header.Size = sizeof(struct aac_fib_header) + datasize; |
| 984263bc | 2080 | fib->Header.SenderSize = sizeof(struct aac_fib); |
| d9773475 | 2081 | fib->Header.SenderFibAddress = 0; /* Not needed */ |
| 984263bc MD |
2082 | fib->Header.ReceiverFibAddress = sc->aac_common_busaddr + |
| 2083 | offsetof(struct aac_common, | |
| 2084 | ac_sync_fib); | |
| 2085 | ||
| 2086 | /* | |
| 2087 | * Give the FIB to the controller, wait for a response. | |
| 2088 | */ | |
| 2089 | if (aac_sync_command(sc, AAC_MONKER_SYNCFIB, | |
| 2090 | fib->Header.ReceiverFibAddress, 0, 0, 0, NULL)) { | |
| e9ae7f4f | 2091 | fwprintf(sc, HBA_FLAGS_DBG_ERROR_B, "IO error"); |
| 984263bc MD |
2092 | return(EIO); |
| 2093 | } | |
| 2094 | ||
| 2095 | return (0); | |
| 2096 | } | |
| 2097 | ||
| 2098 | /* | |
| 2099 | * Adapter-space FIB queue manipulation | |
| 2100 | * | |
| 2101 | * Note that the queue implementation here is a little funky; neither the PI or | |
| 2102 | * CI will ever be zero. This behaviour is a controller feature. | |
| 2103 | */ | |
| 2104 | static struct { | |
| 2105 | int size; | |
| 2106 | int notify; | |
| 2107 | } aac_qinfo[] = { | |
| 2108 | {AAC_HOST_NORM_CMD_ENTRIES, AAC_DB_COMMAND_NOT_FULL}, | |
| 2109 | {AAC_HOST_HIGH_CMD_ENTRIES, 0}, | |
| 2110 | {AAC_ADAP_NORM_CMD_ENTRIES, AAC_DB_COMMAND_READY}, | |
| 2111 | {AAC_ADAP_HIGH_CMD_ENTRIES, 0}, | |
| 2112 | {AAC_HOST_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_NOT_FULL}, | |
| 2113 | {AAC_HOST_HIGH_RESP_ENTRIES, 0}, | |
| 2114 | {AAC_ADAP_NORM_RESP_ENTRIES, AAC_DB_RESPONSE_READY}, | |
| 2115 | {AAC_ADAP_HIGH_RESP_ENTRIES, 0} | |
| 2116 | }; | |
| 2117 | ||
| 2118 | /* | |
| 2119 | * Atomically insert an entry into the nominated queue, returns 0 on success or | |
| 2120 | * EBUSY if the queue is full. | |
| 2121 | * | |
| 2122 | * Note: it would be more efficient to defer notifying the controller in | |
| 2123 | * the case where we may be inserting several entries in rapid succession, | |
| 2124 | * but implementing this usefully may be difficult (it would involve a | |
| 2125 | * separate queue/notify interface). | |
| 2126 | */ | |
| 2127 | static int | |
| 2128 | aac_enqueue_fib(struct aac_softc *sc, int queue, struct aac_command *cm) | |
| 2129 | { | |
| 2130 | u_int32_t pi, ci; | |
| 7f2216bc | 2131 | int error; |
| 984263bc MD |
2132 | u_int32_t fib_size; |
| 2133 | u_int32_t fib_addr; | |
| 2134 | ||
| e9ae7f4f | 2135 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2136 | |
| d9773475 | 2137 | fib_size = cm->cm_fib->Header.Size; |
| 984263bc MD |
2138 | fib_addr = cm->cm_fib->Header.ReceiverFibAddress; |
| 2139 | ||
| 984263bc MD |
2140 | /* get the producer/consumer indices */ |
| 2141 | pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; | |
| 2142 | ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; | |
| 2143 | ||
| 2144 | /* wrap the queue? */ | |
| 2145 | if (pi >= aac_qinfo[queue].size) | |
| 2146 | pi = 0; | |
| 2147 | ||
| 2148 | /* check for queue full */ | |
| 2149 | if ((pi + 1) == ci) { | |
| 2150 | error = EBUSY; | |
| 2151 | goto out; | |
| 2152 | } | |
| e9ae7f4f | 2153 | |
| 158dbeb8 MD |
2154 | /* |
| 2155 | * To avoid a race with its completion interrupt, place this command on | |
| 2156 | * the busy queue prior to advertising it to the controller. | |
| 2157 | */ | |
| 2158 | aac_enqueue_busy(cm); | |
| 2159 | ||
| 984263bc MD |
2160 | /* populate queue entry */ |
| 2161 | (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; | |
| 2162 | (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; | |
| 2163 | ||
| 2164 | /* update producer index */ | |
| 2165 | sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; | |
| 2166 | ||
| 984263bc MD |
2167 | /* notify the adapter if we know how */ |
| 2168 | if (aac_qinfo[queue].notify != 0) | |
| 2169 | AAC_QNOTIFY(sc, aac_qinfo[queue].notify); | |
| 2170 | ||
| 2171 | error = 0; | |
| 2172 | ||
| 2173 | out: | |
| 984263bc MD |
2174 | return(error); |
| 2175 | } | |
| 2176 | ||
| 2177 | /* | |
| 2178 | * Atomically remove one entry from the nominated queue, returns 0 on | |
| 2179 | * success or ENOENT if the queue is empty. | |
| 2180 | */ | |
| 2181 | static int | |
| 2182 | aac_dequeue_fib(struct aac_softc *sc, int queue, u_int32_t *fib_size, | |
| 2183 | struct aac_fib **fib_addr) | |
| 2184 | { | |
| 2185 | u_int32_t pi, ci; | |
| d9773475 | 2186 | u_int32_t fib_index; |
| 7f2216bc | 2187 | int error; |
| 984263bc MD |
2188 | int notify; |
| 2189 | ||
| e9ae7f4f | 2190 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2191 | |
| 984263bc MD |
2192 | /* get the producer/consumer indices */ |
| 2193 | pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; | |
| 2194 | ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; | |
| 2195 | ||
| 2196 | /* check for queue empty */ | |
| 2197 | if (ci == pi) { | |
| 2198 | error = ENOENT; | |
| 2199 | goto out; | |
| 2200 | } | |
| 158dbeb8 MD |
2201 | |
| 2202 | /* wrap the pi so the following test works */ | |
| 2203 | if (pi >= aac_qinfo[queue].size) | |
| 2204 | pi = 0; | |
| 2205 | ||
| 984263bc MD |
2206 | notify = 0; |
| 2207 | if (ci == pi + 1) | |
| 2208 | notify++; | |
| 2209 | ||
| 2210 | /* wrap the queue? */ | |
| 2211 | if (ci >= aac_qinfo[queue].size) | |
| 2212 | ci = 0; | |
| 2213 | ||
| 2214 | /* fetch the entry */ | |
| 2215 | *fib_size = (sc->aac_qentries[queue] + ci)->aq_fib_size; | |
| 984263bc | 2216 | |
| d9773475 PA |
2217 | switch (queue) { |
| 2218 | case AAC_HOST_NORM_CMD_QUEUE: | |
| 2219 | case AAC_HOST_HIGH_CMD_QUEUE: | |
| 2220 | /* | |
| 2221 | * The aq_fib_addr is only 32 bits wide so it can't be counted | |
| 2222 | * on to hold an address. For AIF's, the adapter assumes | |
| 2223 | * that it's giving us an address into the array of AIF fibs. | |
| 2224 | * Therefore, we have to convert it to an index. | |
| 2225 | */ | |
| 2226 | fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr / | |
| 2227 | sizeof(struct aac_fib); | |
| 2228 | *fib_addr = &sc->aac_common->ac_fibs[fib_index]; | |
| 2229 | break; | |
| 2230 | ||
| 2231 | case AAC_HOST_NORM_RESP_QUEUE: | |
| 2232 | case AAC_HOST_HIGH_RESP_QUEUE: | |
| 2233 | { | |
| 2234 | struct aac_command *cm; | |
| 2235 | ||
| 2236 | /* | |
| 2237 | * As above, an index is used instead of an actual address. | |
| 2238 | * Gotta shift the index to account for the fast response | |
| 2239 | * bit. No other correction is needed since this value was | |
| 2240 | * originally provided by the driver via the SenderFibAddress | |
| 2241 | * field. | |
| 2242 | */ | |
| 2243 | fib_index = (sc->aac_qentries[queue] + ci)->aq_fib_addr; | |
| 2244 | cm = sc->aac_commands + (fib_index >> 2); | |
| 2245 | *fib_addr = cm->cm_fib; | |
| 2246 | ||
| 2247 | /* | |
| 2248 | * Is this a fast response? If it is, update the fib fields in | |
| 2249 | * local memory since the whole fib isn't DMA'd back up. | |
| 2250 | */ | |
| 2251 | if (fib_index & 0x01) { | |
| 2252 | (*fib_addr)->Header.XferState |= AAC_FIBSTATE_DONEADAP; | |
| 2253 | *((u_int32_t*)((*fib_addr)->data)) = AAC_ERROR_NORMAL; | |
| 2254 | } | |
| 2255 | break; | |
| 2256 | } | |
| 2257 | default: | |
| 2258 | panic("Invalid queue in aac_dequeue_fib()"); | |
| 2259 | break; | |
| 984263bc | 2260 | } |
| d9773475 | 2261 | |
| 984263bc MD |
2262 | /* update consumer index */ |
| 2263 | sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX] = ci + 1; | |
| 2264 | ||
| 2265 | /* if we have made the queue un-full, notify the adapter */ | |
| 2266 | if (notify && (aac_qinfo[queue].notify != 0)) | |
| 2267 | AAC_QNOTIFY(sc, aac_qinfo[queue].notify); | |
| 2268 | error = 0; | |
| 2269 | ||
| 2270 | out: | |
| 984263bc MD |
2271 | return(error); |
| 2272 | } | |
| 2273 | ||
| 2274 | /* | |
| 2275 | * Put our response to an Adapter Initialed Fib on the response queue | |
| 2276 | */ | |
| 2277 | static int | |
| 2278 | aac_enqueue_response(struct aac_softc *sc, int queue, struct aac_fib *fib) | |
| 2279 | { | |
| 2280 | u_int32_t pi, ci; | |
| 7f2216bc | 2281 | int error; |
| 984263bc MD |
2282 | u_int32_t fib_size; |
| 2283 | u_int32_t fib_addr; | |
| 2284 | ||
| e9ae7f4f | 2285 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
2286 | |
| 2287 | /* Tell the adapter where the FIB is */ | |
| d9773475 | 2288 | fib_size = fib->Header.Size; |
| 984263bc MD |
2289 | fib_addr = fib->Header.SenderFibAddress; |
| 2290 | fib->Header.ReceiverFibAddress = fib_addr; | |
| 2291 | ||
| 984263bc MD |
2292 | /* get the producer/consumer indices */ |
| 2293 | pi = sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX]; | |
| 2294 | ci = sc->aac_queues->qt_qindex[queue][AAC_CONSUMER_INDEX]; | |
| 2295 | ||
| 2296 | /* wrap the queue? */ | |
| 2297 | if (pi >= aac_qinfo[queue].size) | |
| 2298 | pi = 0; | |
| 2299 | ||
| 2300 | /* check for queue full */ | |
| 2301 | if ((pi + 1) == ci) { | |
| 2302 | error = EBUSY; | |
| 2303 | goto out; | |
| 2304 | } | |
| 2305 | ||
| 2306 | /* populate queue entry */ | |
| 2307 | (sc->aac_qentries[queue] + pi)->aq_fib_size = fib_size; | |
| 2308 | (sc->aac_qentries[queue] + pi)->aq_fib_addr = fib_addr; | |
| 2309 | ||
| 2310 | /* update producer index */ | |
| 2311 | sc->aac_queues->qt_qindex[queue][AAC_PRODUCER_INDEX] = pi + 1; | |
| 2312 | ||
| 2313 | /* notify the adapter if we know how */ | |
| 2314 | if (aac_qinfo[queue].notify != 0) | |
| 2315 | AAC_QNOTIFY(sc, aac_qinfo[queue].notify); | |
| 2316 | ||
| 2317 | error = 0; | |
| 2318 | ||
| 2319 | out: | |
| 984263bc MD |
2320 | return(error); |
| 2321 | } | |
| 2322 | ||
| 2323 | /* | |
| 2324 | * Check for commands that have been outstanding for a suspiciously long time, | |
| 2325 | * and complain about them. | |
| 2326 | */ | |
| 2327 | static void | |
| e9ae7f4f | 2328 | aac_timeout(struct aac_softc *sc) |
| 984263bc | 2329 | { |
| 984263bc MD |
2330 | struct aac_command *cm; |
| 2331 | time_t deadline; | |
| 158dbeb8 | 2332 | int timedout, code; |
| e9ae7f4f | 2333 | |
| 984263bc | 2334 | /* |
| d9773475 | 2335 | * Traverse the busy command list, bitch about late commands once |
| 984263bc MD |
2336 | * only. |
| 2337 | */ | |
| 158dbeb8 | 2338 | timedout = 0; |
| 984263bc | 2339 | deadline = time_second - AAC_CMD_TIMEOUT; |
| 984263bc MD |
2340 | TAILQ_FOREACH(cm, &sc->aac_busy, cm_link) { |
| 2341 | if ((cm->cm_timestamp < deadline) | |
| e9ae7f4f | 2342 | && !(cm->cm_flags & AAC_CMD_TIMEDOUT)) { |
| 984263bc MD |
2343 | cm->cm_flags |= AAC_CMD_TIMEDOUT; |
| 2344 | device_printf(sc->aac_dev, | |
| e9ae7f4f SW |
2345 | "COMMAND %p (TYPE %d) TIMEOUT AFTER %d SECONDS\n", |
| 2346 | cm, cm->cm_fib->Header.Command, | |
| 2347 | (int)(time_second-cm->cm_timestamp)); | |
| 984263bc | 2348 | AAC_PRINT_FIB(sc, cm->cm_fib); |
| 158dbeb8 MD |
2349 | timedout++; |
| 2350 | } | |
| 2351 | } | |
| e9ae7f4f | 2352 | |
| 158dbeb8 MD |
2353 | if (timedout) { |
| 2354 | code = AAC_GET_FWSTATUS(sc); | |
| 2355 | if (code != AAC_UP_AND_RUNNING) { | |
| 2356 | device_printf(sc->aac_dev, "WARNING! Controller is no " | |
| 2357 | "longer running! code= 0x%x\n", code); | |
| 984263bc MD |
2358 | } |
| 2359 | } | |
| e9ae7f4f | 2360 | return; |
| 984263bc MD |
2361 | } |
| 2362 | ||
| 2363 | /* | |
| 2364 | * Interface Function Vectors | |
| 2365 | */ | |
| 2366 | ||
| 2367 | /* | |
| 2368 | * Read the current firmware status word. | |
| 2369 | */ | |
| 2370 | static int | |
| 2371 | aac_sa_get_fwstatus(struct aac_softc *sc) | |
| 2372 | { | |
| e9ae7f4f | 2373 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2374 | |
| e9ae7f4f | 2375 | return(AAC_MEM0_GETREG4(sc, AAC_SA_FWSTATUS)); |
| 984263bc MD |
2376 | } |
| 2377 | ||
| 2378 | static int | |
| 2379 | aac_rx_get_fwstatus(struct aac_softc *sc) | |
| 2380 | { | |
| e9ae7f4f | 2381 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2382 | |
| e9ae7f4f SW |
2383 | return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? |
| 2384 | AAC_RX_OMR0 : AAC_RX_FWSTATUS)); | |
| 984263bc MD |
2385 | } |
| 2386 | ||
| d9773475 PA |
2387 | static int |
| 2388 | aac_rkt_get_fwstatus(struct aac_softc *sc) | |
| 2389 | { | |
| e9ae7f4f | 2390 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2391 | |
| e9ae7f4f SW |
2392 | return(AAC_MEM0_GETREG4(sc, sc->flags & AAC_FLAGS_NEW_COMM ? |
| 2393 | AAC_RKT_OMR0 : AAC_RKT_FWSTATUS)); | |
| d9773475 PA |
2394 | } |
| 2395 | ||
| 984263bc MD |
2396 | /* |
| 2397 | * Notify the controller of a change in a given queue | |
| 2398 | */ | |
| 2399 | ||
| 2400 | static void | |
| 2401 | aac_sa_qnotify(struct aac_softc *sc, int qbit) | |
| 2402 | { | |
| e9ae7f4f | 2403 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2404 | |
| e9ae7f4f | 2405 | AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL1_SET, qbit); |
| 984263bc MD |
2406 | } |
| 2407 | ||
| 2408 | static void | |
| 2409 | aac_rx_qnotify(struct aac_softc *sc, int qbit) | |
| 2410 | { | |
| e9ae7f4f | 2411 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2412 | |
| e9ae7f4f | 2413 | AAC_MEM0_SETREG4(sc, AAC_RX_IDBR, qbit); |
| 984263bc MD |
2414 | } |
| 2415 | ||
| d9773475 PA |
2416 | static void |
| 2417 | aac_rkt_qnotify(struct aac_softc *sc, int qbit) | |
| 2418 | { | |
| e9ae7f4f | 2419 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2420 | |
| e9ae7f4f | 2421 | AAC_MEM0_SETREG4(sc, AAC_RKT_IDBR, qbit); |
| d9773475 PA |
2422 | } |
| 2423 | ||
| 984263bc MD |
2424 | /* |
| 2425 | * Get the interrupt reason bits | |
| 2426 | */ | |
| 2427 | static int | |
| 2428 | aac_sa_get_istatus(struct aac_softc *sc) | |
| 2429 | { | |
| e9ae7f4f | 2430 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2431 | |
| e9ae7f4f | 2432 | return(AAC_MEM0_GETREG2(sc, AAC_SA_DOORBELL0)); |
| 984263bc MD |
2433 | } |
| 2434 | ||
| 2435 | static int | |
| 2436 | aac_rx_get_istatus(struct aac_softc *sc) | |
| 2437 | { | |
| e9ae7f4f | 2438 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2439 | |
| e9ae7f4f | 2440 | return(AAC_MEM0_GETREG4(sc, AAC_RX_ODBR)); |
| 984263bc MD |
2441 | } |
| 2442 | ||
| d9773475 PA |
2443 | static int |
| 2444 | aac_rkt_get_istatus(struct aac_softc *sc) | |
| 2445 | { | |
| e9ae7f4f | 2446 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2447 | |
| e9ae7f4f | 2448 | return(AAC_MEM0_GETREG4(sc, AAC_RKT_ODBR)); |
| d9773475 PA |
2449 | } |
| 2450 | ||
| 984263bc MD |
2451 | /* |
| 2452 | * Clear some interrupt reason bits | |
| 2453 | */ | |
| 2454 | static void | |
| 2455 | aac_sa_clear_istatus(struct aac_softc *sc, int mask) | |
| 2456 | { | |
| e9ae7f4f | 2457 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2458 | |
| e9ae7f4f | 2459 | AAC_MEM0_SETREG2(sc, AAC_SA_DOORBELL0_CLEAR, mask); |
| 984263bc MD |
2460 | } |
| 2461 | ||
| 2462 | static void | |
| 2463 | aac_rx_clear_istatus(struct aac_softc *sc, int mask) | |
| 2464 | { | |
| e9ae7f4f | 2465 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2466 | |
| e9ae7f4f | 2467 | AAC_MEM0_SETREG4(sc, AAC_RX_ODBR, mask); |
| 984263bc MD |
2468 | } |
| 2469 | ||
| d9773475 PA |
2470 | static void |
| 2471 | aac_rkt_clear_istatus(struct aac_softc *sc, int mask) | |
| 2472 | { | |
| e9ae7f4f | 2473 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2474 | |
| e9ae7f4f | 2475 | AAC_MEM0_SETREG4(sc, AAC_RKT_ODBR, mask); |
| d9773475 PA |
2476 | } |
| 2477 | ||
| 984263bc MD |
2478 | /* |
| 2479 | * Populate the mailbox and set the command word | |
| 2480 | */ | |
| 2481 | static void | |
| 2482 | aac_sa_set_mailbox(struct aac_softc *sc, u_int32_t command, | |
| 2483 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) | |
| 2484 | { | |
| e9ae7f4f | 2485 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2486 | |
| e9ae7f4f SW |
2487 | AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX, command); |
| 2488 | AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 4, arg0); | |
| 2489 | AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 8, arg1); | |
| 2490 | AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 12, arg2); | |
| 2491 | AAC_MEM1_SETREG4(sc, AAC_SA_MAILBOX + 16, arg3); | |
| 984263bc MD |
2492 | } |
| 2493 | ||
| 2494 | static void | |
| 2495 | aac_rx_set_mailbox(struct aac_softc *sc, u_int32_t command, | |
| 2496 | u_int32_t arg0, u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) | |
| 2497 | { | |
| e9ae7f4f | 2498 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2499 | |
| e9ae7f4f SW |
2500 | AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX, command); |
| 2501 | AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 4, arg0); | |
| 2502 | AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 8, arg1); | |
| 2503 | AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 12, arg2); | |
| 2504 | AAC_MEM1_SETREG4(sc, AAC_RX_MAILBOX + 16, arg3); | |
| 984263bc MD |
2505 | } |
| 2506 | ||
| d9773475 PA |
2507 | static void |
| 2508 | aac_rkt_set_mailbox(struct aac_softc *sc, u_int32_t command, u_int32_t arg0, | |
| 2509 | u_int32_t arg1, u_int32_t arg2, u_int32_t arg3) | |
| 2510 | { | |
| e9ae7f4f | 2511 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2512 | |
| e9ae7f4f SW |
2513 | AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX, command); |
| 2514 | AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 4, arg0); | |
| 2515 | AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 8, arg1); | |
| 2516 | AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 12, arg2); | |
| 2517 | AAC_MEM1_SETREG4(sc, AAC_RKT_MAILBOX + 16, arg3); | |
| d9773475 PA |
2518 | } |
| 2519 | ||
| 984263bc MD |
2520 | /* |
| 2521 | * Fetch the immediate command status word | |
| 2522 | */ | |
| 2523 | static int | |
| 2524 | aac_sa_get_mailbox(struct aac_softc *sc, int mb) | |
| 2525 | { | |
| e9ae7f4f | 2526 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2527 | |
| e9ae7f4f | 2528 | return(AAC_MEM1_GETREG4(sc, AAC_SA_MAILBOX + (mb * 4))); |
| 984263bc MD |
2529 | } |
| 2530 | ||
| 2531 | static int | |
| 2532 | aac_rx_get_mailbox(struct aac_softc *sc, int mb) | |
| 2533 | { | |
| e9ae7f4f | 2534 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2535 | |
| e9ae7f4f | 2536 | return(AAC_MEM1_GETREG4(sc, AAC_RX_MAILBOX + (mb * 4))); |
| 984263bc MD |
2537 | } |
| 2538 | ||
| d9773475 PA |
2539 | static int |
| 2540 | aac_rkt_get_mailbox(struct aac_softc *sc, int mb) | |
| 2541 | { | |
| e9ae7f4f | 2542 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2543 | |
| e9ae7f4f | 2544 | return(AAC_MEM1_GETREG4(sc, AAC_RKT_MAILBOX + (mb * 4))); |
| d9773475 PA |
2545 | } |
| 2546 | ||
| 984263bc MD |
2547 | /* |
| 2548 | * Set/clear interrupt masks | |
| 2549 | */ | |
| 2550 | static void | |
| 2551 | aac_sa_set_interrupts(struct aac_softc *sc, int enable) | |
| 2552 | { | |
| e9ae7f4f | 2553 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); |
| 984263bc MD |
2554 | |
| 2555 | if (enable) { | |
| e9ae7f4f | 2556 | AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_CLEAR, AAC_DB_INTERRUPTS); |
| 984263bc | 2557 | } else { |
| e9ae7f4f | 2558 | AAC_MEM0_SETREG2((sc), AAC_SA_MASK0_SET, ~0); |
| 984263bc MD |
2559 | } |
| 2560 | } | |
| 2561 | ||
| 2562 | static void | |
| 2563 | aac_rx_set_interrupts(struct aac_softc *sc, int enable) | |
| 2564 | { | |
| e9ae7f4f | 2565 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); |
| 984263bc MD |
2566 | |
| 2567 | if (enable) { | |
| d9773475 | 2568 | if (sc->flags & AAC_FLAGS_NEW_COMM) |
| e9ae7f4f | 2569 | AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INT_NEW_COMM); |
| d9773475 | 2570 | else |
| e9ae7f4f | 2571 | AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~AAC_DB_INTERRUPTS); |
| 984263bc | 2572 | } else { |
| e9ae7f4f | 2573 | AAC_MEM0_SETREG4(sc, AAC_RX_OIMR, ~0); |
| 984263bc MD |
2574 | } |
| 2575 | } | |
| 2576 | ||
| d9773475 PA |
2577 | static void |
| 2578 | aac_rkt_set_interrupts(struct aac_softc *sc, int enable) | |
| 2579 | { | |
| e9ae7f4f | 2580 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "%sable interrupts", enable ? "en" : "dis"); |
| d9773475 PA |
2581 | |
| 2582 | if (enable) { | |
| 2583 | if (sc->flags & AAC_FLAGS_NEW_COMM) | |
| e9ae7f4f | 2584 | AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INT_NEW_COMM); |
| d9773475 | 2585 | else |
| e9ae7f4f | 2586 | AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~AAC_DB_INTERRUPTS); |
| d9773475 | 2587 | } else { |
| e9ae7f4f | 2588 | AAC_MEM0_SETREG4(sc, AAC_RKT_OIMR, ~0); |
| d9773475 PA |
2589 | } |
| 2590 | } | |
| 2591 | ||
| 2592 | /* | |
| 2593 | * New comm. interface: Send command functions | |
| 2594 | */ | |
| 2595 | static int | |
| 2596 | aac_rx_send_command(struct aac_softc *sc, struct aac_command *cm) | |
| 2597 | { | |
| 2598 | u_int32_t index, device; | |
| 2599 | ||
| e9ae7f4f | 2600 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); |
| d9773475 | 2601 | |
| e9ae7f4f | 2602 | index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); |
| d9773475 | 2603 | if (index == 0xffffffffL) |
| e9ae7f4f | 2604 | index = AAC_MEM0_GETREG4(sc, AAC_RX_IQUE); |
| d9773475 PA |
2605 | if (index == 0xffffffffL) |
| 2606 | return index; | |
| 2607 | aac_enqueue_busy(cm); | |
| 2608 | device = index; | |
| e9ae7f4f | 2609 | AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); |
| d9773475 | 2610 | device += 4; |
| e9ae7f4f | 2611 | AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); |
| d9773475 | 2612 | device += 4; |
| e9ae7f4f SW |
2613 | AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); |
| 2614 | AAC_MEM0_SETREG4(sc, AAC_RX_IQUE, index); | |
| d9773475 PA |
2615 | return 0; |
| 2616 | } | |
| 2617 | ||
| 2618 | static int | |
| 2619 | aac_rkt_send_command(struct aac_softc *sc, struct aac_command *cm) | |
| 2620 | { | |
| 2621 | u_int32_t index, device; | |
| 2622 | ||
| e9ae7f4f | 2623 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "send command (new comm.)"); |
| d9773475 | 2624 | |
| e9ae7f4f | 2625 | index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); |
| d9773475 | 2626 | if (index == 0xffffffffL) |
| e9ae7f4f | 2627 | index = AAC_MEM0_GETREG4(sc, AAC_RKT_IQUE); |
| d9773475 PA |
2628 | if (index == 0xffffffffL) |
| 2629 | return index; | |
| 2630 | aac_enqueue_busy(cm); | |
| 2631 | device = index; | |
| e9ae7f4f | 2632 | AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys & 0xffffffffUL)); |
| d9773475 | 2633 | device += 4; |
| e9ae7f4f | 2634 | AAC_MEM1_SETREG4(sc, device, (u_int32_t)(cm->cm_fibphys >> 32)); |
| d9773475 | 2635 | device += 4; |
| e9ae7f4f SW |
2636 | AAC_MEM1_SETREG4(sc, device, cm->cm_fib->Header.Size); |
| 2637 | AAC_MEM0_SETREG4(sc, AAC_RKT_IQUE, index); | |
| d9773475 PA |
2638 | return 0; |
| 2639 | } | |
| 2640 | ||
| 2641 | /* | |
| 2642 | * New comm. interface: get, set outbound queue index | |
| 2643 | */ | |
| 2644 | static int | |
| 2645 | aac_rx_get_outb_queue(struct aac_softc *sc) | |
| 2646 | { | |
| e9ae7f4f | 2647 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2648 | |
| e9ae7f4f | 2649 | return(AAC_MEM0_GETREG4(sc, AAC_RX_OQUE)); |
| d9773475 PA |
2650 | } |
| 2651 | ||
| 2652 | static int | |
| 2653 | aac_rkt_get_outb_queue(struct aac_softc *sc) | |
| 2654 | { | |
| e9ae7f4f | 2655 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2656 | |
| e9ae7f4f | 2657 | return(AAC_MEM0_GETREG4(sc, AAC_RKT_OQUE)); |
| d9773475 PA |
2658 | } |
| 2659 | ||
| 2660 | static void | |
| 2661 | aac_rx_set_outb_queue(struct aac_softc *sc, int index) | |
| 2662 | { | |
| e9ae7f4f | 2663 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2664 | |
| e9ae7f4f | 2665 | AAC_MEM0_SETREG4(sc, AAC_RX_OQUE, index); |
| d9773475 PA |
2666 | } |
| 2667 | ||
| 2668 | static void | |
| 2669 | aac_rkt_set_outb_queue(struct aac_softc *sc, int index) | |
| 2670 | { | |
| e9ae7f4f | 2671 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| d9773475 | 2672 | |
| e9ae7f4f | 2673 | AAC_MEM0_SETREG4(sc, AAC_RKT_OQUE, index); |
| d9773475 PA |
2674 | } |
| 2675 | ||
| 984263bc MD |
2676 | /* |
| 2677 | * Debugging and Diagnostics | |
| 2678 | */ | |
| 2679 | ||
| 2680 | /* | |
| 2681 | * Print some information about the controller. | |
| 2682 | */ | |
| 2683 | static void | |
| 2684 | aac_describe_controller(struct aac_softc *sc) | |
| 2685 | { | |
| 2686 | struct aac_fib *fib; | |
| 2687 | struct aac_adapter_info *info; | |
| e9ae7f4f | 2688 | char *adapter_type = "Adaptec RAID controller"; |
| 984263bc | 2689 | |
| e9ae7f4f | 2690 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc | 2691 | |
| e9ae7f4f | 2692 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| d9773475 | 2693 | aac_alloc_sync_fib(sc, &fib); |
| 984263bc MD |
2694 | |
| 2695 | fib->data[0] = 0; | |
| 2696 | if (aac_sync_fib(sc, RequestAdapterInfo, 0, fib, 1)) { | |
| 2697 | device_printf(sc->aac_dev, "RequestAdapterInfo failed\n"); | |
| 2698 | aac_release_sync_fib(sc); | |
| e9ae7f4f | 2699 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc MD |
2700 | return; |
| 2701 | } | |
| 984263bc MD |
2702 | |
| 2703 | /* save the kernel revision structure for later use */ | |
| d9773475 | 2704 | info = (struct aac_adapter_info *)&fib->data[0]; |
| 984263bc | 2705 | sc->aac_revision = info->KernelRevision; |
| 984263bc | 2706 | |
| d9773475 PA |
2707 | if (bootverbose) { |
| 2708 | device_printf(sc->aac_dev, "%s %dMHz, %dMB memory " | |
| 2709 | "(%dMB cache, %dMB execution), %s\n", | |
| 2710 | aac_describe_code(aac_cpu_variant, info->CpuVariant), | |
| 2711 | info->ClockSpeed, info->TotalMem / (1024 * 1024), | |
| 2712 | info->BufferMem / (1024 * 1024), | |
| 2713 | info->ExecutionMem / (1024 * 1024), | |
| 2714 | aac_describe_code(aac_battery_platform, | |
| 2715 | info->batteryPlatform)); | |
| 2716 | ||
| 2717 | device_printf(sc->aac_dev, | |
| 2718 | "Kernel %d.%d-%d, Build %d, S/N %6X\n", | |
| 2719 | info->KernelRevision.external.comp.major, | |
| 2720 | info->KernelRevision.external.comp.minor, | |
| 2721 | info->KernelRevision.external.comp.dash, | |
| 2722 | info->KernelRevision.buildNumber, | |
| 2723 | (u_int32_t)(info->SerialNumber & 0xffffff)); | |
| 984263bc | 2724 | |
| 984263bc MD |
2725 | device_printf(sc->aac_dev, "Supported Options=%b\n", |
| 2726 | sc->supported_options, | |
| 2727 | "\20" | |
| 2728 | "\1SNAPSHOT" | |
| 2729 | "\2CLUSTERS" | |
| 2730 | "\3WCACHE" | |
| 2731 | "\4DATA64" | |
| 2732 | "\5HOSTTIME" | |
| 2733 | "\6RAID50" | |
| 2734 | "\7WINDOW4GB" | |
| 2735 | "\10SCSIUPGD" | |
| 2736 | "\11SOFTERR" | |
| 2737 | "\12NORECOND" | |
| 2738 | "\13SGMAP64" | |
| 2739 | "\14ALARM" | |
| d9773475 PA |
2740 | "\15NONDASD" |
| 2741 | "\16SCSIMGT" | |
| 2742 | "\17RAIDSCSI" | |
| 2743 | "\21ADPTINFO" | |
| 2744 | "\22NEWCOMM" | |
| 2745 | "\23ARRAY64BIT" | |
| 2746 | "\24HEATSENSOR"); | |
| 984263bc | 2747 | } |
| e9ae7f4f SW |
2748 | |
| 2749 | if (sc->supported_options & AAC_SUPPORTED_SUPPLEMENT_ADAPTER_INFO) { | |
| 2750 | fib->data[0] = 0; | |
| 2751 | if (aac_sync_fib(sc, RequestSupplementAdapterInfo, 0, fib, 1)) | |
| 2752 | device_printf(sc->aac_dev, | |
| 2753 | "RequestSupplementAdapterInfo failed\n"); | |
| 2754 | else | |
| 2755 | adapter_type = ((struct aac_supplement_adapter_info *) | |
| 2756 | &fib->data[0])->AdapterTypeText; | |
| 2757 | } | |
| 2758 | device_printf(sc->aac_dev, "%s, aac driver %d.%d.%d-%d\n", | |
| 2759 | adapter_type, | |
| 2760 | AAC_DRIVER_MAJOR_VERSION, AAC_DRIVER_MINOR_VERSION, | |
| 2761 | AAC_DRIVER_BUGFIX_LEVEL, AAC_DRIVER_BUILD); | |
| 2762 | ||
| d9773475 | 2763 | aac_release_sync_fib(sc); |
| e9ae7f4f | 2764 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc MD |
2765 | } |
| 2766 | ||
| 2767 | /* | |
| 2768 | * Look up a text description of a numeric error code and return a pointer to | |
| 2769 | * same. | |
| 2770 | */ | |
| 2771 | static char * | |
| 2772 | aac_describe_code(struct aac_code_lookup *table, u_int32_t code) | |
| 2773 | { | |
| 2774 | int i; | |
| 2775 | ||
| 2776 | for (i = 0; table[i].string != NULL; i++) | |
| 2777 | if (table[i].code == code) | |
| 2778 | return(table[i].string); | |
| 2779 | return(table[i + 1].string); | |
| 2780 | } | |
| 2781 | ||
| 2782 | /* | |
| 2783 | * Management Interface | |
| 2784 | */ | |
| 2785 | ||
| 2786 | static int | |
| fef8985e | 2787 | aac_open(struct dev_open_args *ap) |
| 984263bc | 2788 | { |
| b13267a5 | 2789 | cdev_t dev = ap->a_head.a_dev; |
| 984263bc MD |
2790 | struct aac_softc *sc; |
| 2791 | ||
| 984263bc | 2792 | sc = dev->si_drv1; |
| e9ae7f4f SW |
2793 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 2794 | device_busy(sc->aac_dev); | |
| 984263bc MD |
2795 | |
| 2796 | return 0; | |
| 2797 | } | |
| 2798 | ||
| 2799 | static int | |
| fef8985e | 2800 | aac_ioctl(struct dev_ioctl_args *ap) |
| 984263bc | 2801 | { |
| fef8985e | 2802 | caddr_t arg = ap->a_data; |
| e9ae7f4f SW |
2803 | cdev_t dev = ap->a_head.a_dev; |
| 2804 | u_long cmd = ap->a_cmd; | |
| 2805 | union aac_statrequest *as; | |
| 2806 | struct aac_softc *sc; | |
| 984263bc | 2807 | int error = 0; |
| 984263bc | 2808 | |
| e9ae7f4f SW |
2809 | as = (union aac_statrequest *)arg; |
| 2810 | sc = dev->si_drv1; | |
| 2811 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 984263bc | 2812 | |
| e9ae7f4f SW |
2813 | switch (cmd) { |
| 2814 | case AACIO_STATS: | |
| 984263bc MD |
2815 | switch (as->as_item) { |
| 2816 | case AACQ_FREE: | |
| 2817 | case AACQ_BIO: | |
| 2818 | case AACQ_READY: | |
| 2819 | case AACQ_BUSY: | |
| 984263bc MD |
2820 | bcopy(&sc->aac_qstat[as->as_item], &as->as_qstat, |
| 2821 | sizeof(struct aac_qstat)); | |
| 2822 | break; | |
| 2823 | default: | |
| 2824 | error = ENOENT; | |
| 2825 | break; | |
| 2826 | } | |
| e9ae7f4f | 2827 | break; |
| 3930af25 | 2828 | |
| 984263bc | 2829 | case FSACTL_SENDFIB: |
| e9ae7f4f SW |
2830 | case FSACTL_SEND_LARGE_FIB: |
| 2831 | arg = *(caddr_t*)arg; | |
| 2832 | case FSACTL_LNX_SENDFIB: | |
| 2833 | case FSACTL_LNX_SEND_LARGE_FIB: | |
| 2834 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SENDFIB"); | |
| 984263bc MD |
2835 | error = aac_ioctl_sendfib(sc, arg); |
| 2836 | break; | |
| e9ae7f4f SW |
2837 | case FSACTL_SEND_RAW_SRB: |
| 2838 | arg = *(caddr_t*)arg; | |
| 2839 | case FSACTL_LNX_SEND_RAW_SRB: | |
| 2840 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_SEND_RAW_SRB"); | |
| 2841 | error = aac_ioctl_send_raw_srb(sc, arg); | |
| 2842 | break; | |
| 984263bc | 2843 | case FSACTL_AIF_THREAD: |
| e9ae7f4f SW |
2844 | case FSACTL_LNX_AIF_THREAD: |
| 2845 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_AIF_THREAD"); | |
| 984263bc MD |
2846 | error = EINVAL; |
| 2847 | break; | |
| 2848 | case FSACTL_OPEN_GET_ADAPTER_FIB: | |
| e9ae7f4f SW |
2849 | arg = *(caddr_t*)arg; |
| 2850 | case FSACTL_LNX_OPEN_GET_ADAPTER_FIB: | |
| 2851 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_OPEN_GET_ADAPTER_FIB"); | |
| 2852 | error = aac_open_aif(sc, arg); | |
| 984263bc MD |
2853 | break; |
| 2854 | case FSACTL_GET_NEXT_ADAPTER_FIB: | |
| e9ae7f4f SW |
2855 | arg = *(caddr_t*)arg; |
| 2856 | case FSACTL_LNX_GET_NEXT_ADAPTER_FIB: | |
| 2857 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_NEXT_ADAPTER_FIB"); | |
| 984263bc MD |
2858 | error = aac_getnext_aif(sc, arg); |
| 2859 | break; | |
| 2860 | case FSACTL_CLOSE_GET_ADAPTER_FIB: | |
| e9ae7f4f SW |
2861 | arg = *(caddr_t*)arg; |
| 2862 | case FSACTL_LNX_CLOSE_GET_ADAPTER_FIB: | |
| 2863 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_CLOSE_GET_ADAPTER_FIB"); | |
| 2864 | error = aac_close_aif(sc, arg); | |
| 984263bc MD |
2865 | break; |
| 2866 | case FSACTL_MINIPORT_REV_CHECK: | |
| e9ae7f4f SW |
2867 | arg = *(caddr_t*)arg; |
| 2868 | case FSACTL_LNX_MINIPORT_REV_CHECK: | |
| 2869 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_MINIPORT_REV_CHECK"); | |
| 984263bc MD |
2870 | error = aac_rev_check(sc, arg); |
| 2871 | break; | |
| 2872 | case FSACTL_QUERY_DISK: | |
| e9ae7f4f SW |
2873 | arg = *(caddr_t*)arg; |
| 2874 | case FSACTL_LNX_QUERY_DISK: | |
| 2875 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_QUERY_DISK"); | |
| 984263bc | 2876 | error = aac_query_disk(sc, arg); |
| d9773475 | 2877 | break; |
| 984263bc | 2878 | case FSACTL_DELETE_DISK: |
| e9ae7f4f | 2879 | case FSACTL_LNX_DELETE_DISK: |
| 984263bc MD |
2880 | /* |
| 2881 | * We don't trust the underland to tell us when to delete a | |
| d9773475 | 2882 | * container, rather we rely on an AIF coming from the |
| 984263bc MD |
2883 | * controller |
| 2884 | */ | |
| 2885 | error = 0; | |
| 2886 | break; | |
| d9773475 PA |
2887 | case FSACTL_GET_PCI_INFO: |
| 2888 | arg = *(caddr_t*)arg; | |
| 2889 | case FSACTL_LNX_GET_PCI_INFO: | |
| e9ae7f4f | 2890 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_PCI_INFO"); |
| d9773475 PA |
2891 | error = aac_get_pci_info(sc, arg); |
| 2892 | break; | |
| e9ae7f4f SW |
2893 | case FSACTL_GET_FEATURES: |
| 2894 | arg = *(caddr_t*)arg; | |
| 2895 | case FSACTL_LNX_GET_FEATURES: | |
| 2896 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "FSACTL_GET_FEATURES"); | |
| 2897 | error = aac_supported_features(sc, arg); | |
| 2898 | break; | |
| 984263bc | 2899 | default: |
| e9ae7f4f | 2900 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "unsupported cmd 0x%lx\n", cmd); |
| 984263bc MD |
2901 | error = EINVAL; |
| 2902 | break; | |
| 2903 | } | |
| 2904 | return(error); | |
| 2905 | } | |
| 2906 | ||
| eda1a08c | 2907 | static struct filterops aac_filterops = |
| e9ae7f4f | 2908 | { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, aac_filter_detach, aac_filter_read }; |
| eda1a08c SG |
2909 | |
| 2910 | static int | |
| 2911 | aac_kqfilter(struct dev_kqfilter_args *ap) | |
| 2912 | { | |
| 2913 | cdev_t dev = ap->a_head.a_dev; | |
| 2914 | struct aac_softc *sc = dev->si_drv1; | |
| 2915 | struct knote *kn = ap->a_kn; | |
| 2916 | struct klist *klist; | |
| 2917 | ||
| 2918 | ap->a_result = 0; | |
| 2919 | ||
| 2920 | switch (kn->kn_filter) { | |
| 2921 | case EVFILT_READ: | |
| 2922 | kn->kn_fop = &aac_filterops; | |
| 2923 | kn->kn_hook = (caddr_t)sc; | |
| 2924 | break; | |
| 2925 | default: | |
| b287d649 | 2926 | ap->a_result = EOPNOTSUPP; |
| eda1a08c SG |
2927 | return (0); |
| 2928 | } | |
| 2929 | ||
| 5b22f1a7 SG |
2930 | klist = &sc->rcv_kq.ki_note; |
| 2931 | knote_insert(klist, kn); | |
| eda1a08c SG |
2932 | |
| 2933 | return (0); | |
| 2934 | } | |
| 2935 | ||
| 2936 | static void | |
| 2937 | aac_filter_detach(struct knote *kn) | |
| 2938 | { | |
| 2939 | struct aac_softc *sc = (struct aac_softc *)kn->kn_hook; | |
| 2940 | struct klist *klist; | |
| 2941 | ||
| 5b22f1a7 SG |
2942 | klist = &sc->rcv_kq.ki_note; |
| 2943 | knote_remove(klist, kn); | |
| eda1a08c SG |
2944 | } |
| 2945 | ||
| 2946 | static int | |
| e9ae7f4f | 2947 | aac_filter_read(struct knote *kn, long hint) |
| eda1a08c | 2948 | { |
| e9ae7f4f SW |
2949 | struct aac_softc *sc; |
| 2950 | struct aac_fib_context *ctx; | |
| eda1a08c | 2951 | |
| e9ae7f4f | 2952 | sc = (struct aac_softc *)kn->kn_hook; |
| eda1a08c | 2953 | |
| e9ae7f4f SW |
2954 | lockmgr(&sc->aac_aifq_lock, LK_EXCLUSIVE); |
| 2955 | for (ctx = sc->fibctx; ctx; ctx = ctx->next) | |
| 2956 | if (ctx->ctx_idx != sc->aifq_idx || ctx->ctx_wrap) | |
| 2957 | return(1); | |
| 2958 | lockmgr(&sc->aac_aifq_lock, LK_RELEASE); | |
| eda1a08c | 2959 | |
| e9ae7f4f SW |
2960 | return (0); |
| 2961 | } | |
| eda1a08c | 2962 | |
| d9773475 PA |
2963 | static void |
| 2964 | aac_ioctl_event(struct aac_softc *sc, struct aac_event *event, void *arg) | |
| 2965 | { | |
| 2966 | ||
| 2967 | switch (event->ev_type) { | |
| 2968 | case AAC_EVENT_CMFREE: | |
| e9ae7f4f | 2969 | KKASSERT(lockstatus(&sc->aac_io_lock, curthread) != 0); |
| d9773475 PA |
2970 | if (aac_alloc_command(sc, (struct aac_command **)arg)) { |
| 2971 | aac_add_event(sc, event); | |
| d9773475 PA |
2972 | return; |
| 2973 | } | |
| 2974 | kfree(event, M_AACBUF); | |
| 2975 | wakeup(arg); | |
| d9773475 PA |
2976 | break; |
| 2977 | default: | |
| 2978 | break; | |
| 2979 | } | |
| 2980 | } | |
| 2981 | ||
| 984263bc MD |
2982 | /* |
| 2983 | * Send a FIB supplied from userspace | |
| 2984 | */ | |
| 2985 | static int | |
| 2986 | aac_ioctl_sendfib(struct aac_softc *sc, caddr_t ufib) | |
| 2987 | { | |
| 2988 | struct aac_command *cm; | |
| 2989 | int size, error; | |
| 2990 | ||
| e9ae7f4f | 2991 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
2992 | |
| 2993 | cm = NULL; | |
| 2994 | ||
| 2995 | /* | |
| 2996 | * Get a command | |
| 2997 | */ | |
| e9ae7f4f | 2998 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 984263bc | 2999 | if (aac_alloc_command(sc, &cm)) { |
| d9773475 PA |
3000 | struct aac_event *event; |
| 3001 | ||
| 3002 | event = kmalloc(sizeof(struct aac_event), M_AACBUF, | |
| 3003 | M_INTWAIT | M_ZERO); | |
| 3004 | event->ev_type = AAC_EVENT_CMFREE; | |
| 3005 | event->ev_callback = aac_ioctl_event; | |
| 3006 | event->ev_arg = &cm; | |
| 3007 | aac_add_event(sc, event); | |
| e9ae7f4f | 3008 | lksleep(&cm, &sc->aac_io_lock, 0, "sendfib", 0); |
| 984263bc | 3009 | } |
| e9ae7f4f | 3010 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 984263bc MD |
3011 | |
| 3012 | /* | |
| 3013 | * Fetch the FIB header, then re-copy to get data as well. | |
| 3014 | */ | |
| 3015 | if ((error = copyin(ufib, cm->cm_fib, | |
| 3016 | sizeof(struct aac_fib_header))) != 0) | |
| 3017 | goto out; | |
| 3018 | size = cm->cm_fib->Header.Size + sizeof(struct aac_fib_header); | |
| e9ae7f4f SW |
3019 | if (size > sc->aac_max_fib_size) { |
| 3020 | device_printf(sc->aac_dev, "incoming FIB oversized (%d > %d)\n", | |
| 3021 | size, sc->aac_max_fib_size); | |
| 3022 | size = sc->aac_max_fib_size; | |
| 984263bc MD |
3023 | } |
| 3024 | if ((error = copyin(ufib, cm->cm_fib, size)) != 0) | |
| 3025 | goto out; | |
| 3026 | cm->cm_fib->Header.Size = size; | |
| 3027 | cm->cm_timestamp = time_second; | |
| 3028 | ||
| 3029 | /* | |
| 3030 | * Pass the FIB to the controller, wait for it to complete. | |
| 3031 | */ | |
| e9ae7f4f SW |
3032 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 3033 | error = aac_wait_command(cm); | |
| 3034 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 3035 | if (error != 0) { | |
| d9773475 PA |
3036 | device_printf(sc->aac_dev, |
| 3037 | "aac_wait_command return %d\n", error); | |
| 984263bc MD |
3038 | goto out; |
| 3039 | } | |
| 3040 | ||
| 3041 | /* | |
| 3042 | * Copy the FIB and data back out to the caller. | |
| 3043 | */ | |
| 3044 | size = cm->cm_fib->Header.Size; | |
| e9ae7f4f SW |
3045 | if (size > sc->aac_max_fib_size) { |
| 3046 | device_printf(sc->aac_dev, "outbound FIB oversized (%d > %d)\n", | |
| 3047 | size, sc->aac_max_fib_size); | |
| 3048 | size = sc->aac_max_fib_size; | |
| 984263bc MD |
3049 | } |
| 3050 | error = copyout(cm->cm_fib, ufib, size); | |
| 3051 | ||
| 3052 | out: | |
| 3053 | if (cm != NULL) { | |
| e9ae7f4f | 3054 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 984263bc | 3055 | aac_release_command(cm); |
| e9ae7f4f SW |
3056 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| 3057 | } | |
| 3058 | return(error); | |
| 3059 | } | |
| 3060 | ||
| 3061 | /* | |
| 3062 | * Send a passthrough FIB supplied from userspace | |
| 3063 | */ | |
| 3064 | static int | |
| 3065 | aac_ioctl_send_raw_srb(struct aac_softc *sc, caddr_t arg) | |
| 3066 | { | |
| 3067 | struct aac_command *cm; | |
| 3068 | struct aac_event *event; | |
| 3069 | struct aac_fib *fib; | |
| 3070 | struct aac_srb *srbcmd, *user_srb; | |
| 3071 | struct aac_sg_entry *sge; | |
| 3072 | struct aac_sg_entry64 *sge64; | |
| 3073 | void *srb_sg_address, *ureply; | |
| 3074 | uint32_t fibsize, srb_sg_bytecount; | |
| 3075 | int error, transfer_data; | |
| 3076 | ||
| 3077 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 3078 | ||
| 3079 | cm = NULL; | |
| 3080 | transfer_data = 0; | |
| 3081 | fibsize = 0; | |
| 3082 | user_srb = (struct aac_srb *)arg; | |
| 3083 | ||
| 3084 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); | |
| 3085 | if (aac_alloc_command(sc, &cm)) { | |
| 3086 | event = kmalloc(sizeof(struct aac_event), M_AACBUF, | |
| 3087 | M_NOWAIT | M_ZERO); | |
| 3088 | if (event == NULL) { | |
| 3089 | error = EBUSY; | |
| 3090 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 3091 | goto out; | |
| 3092 | } | |
| 3093 | event->ev_type = AAC_EVENT_CMFREE; | |
| 3094 | event->ev_callback = aac_ioctl_event; | |
| 3095 | event->ev_arg = &cm; | |
| 3096 | aac_add_event(sc, event); | |
| 3097 | lksleep(cm, &sc->aac_io_lock, 0, "aacraw", 0); | |
| 3098 | } | |
| 3099 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 3100 | ||
| 3101 | cm->cm_data = NULL; | |
| 3102 | fib = cm->cm_fib; | |
| 3103 | srbcmd = (struct aac_srb *)fib->data; | |
| 3104 | error = copyin(&user_srb->data_len, &fibsize, sizeof(uint32_t)); | |
| 3105 | if (error != 0) | |
| 3106 | goto out; | |
| 3107 | if (fibsize > (sc->aac_max_fib_size - sizeof(struct aac_fib_header))) { | |
| 3108 | error = EINVAL; | |
| 3109 | goto out; | |
| 3110 | } | |
| 3111 | error = copyin(user_srb, srbcmd, fibsize); | |
| 3112 | if (error != 0) | |
| 3113 | goto out; | |
| 3114 | srbcmd->function = 0; | |
| 3115 | srbcmd->retry_limit = 0; | |
| 3116 | if (srbcmd->sg_map.SgCount > 1) { | |
| 3117 | error = EINVAL; | |
| 3118 | goto out; | |
| 3119 | } | |
| 3120 | ||
| 3121 | /* Retrieve correct SG entries. */ | |
| 3122 | if (fibsize == (sizeof(struct aac_srb) + | |
| 3123 | srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry))) { | |
| 3124 | sge = srbcmd->sg_map.SgEntry; | |
| 3125 | sge64 = NULL; | |
| 3126 | srb_sg_bytecount = sge->SgByteCount; | |
| 3127 | srb_sg_address = (void *)(uintptr_t)sge->SgAddress; | |
| 3128 | } | |
| 3129 | #ifdef __amd64__ | |
| 3130 | else if (fibsize == (sizeof(struct aac_srb) + | |
| 3131 | srbcmd->sg_map.SgCount * sizeof(struct aac_sg_entry64))) { | |
| 3132 | sge = NULL; | |
| 3133 | sge64 = (struct aac_sg_entry64 *)srbcmd->sg_map.SgEntry; | |
| 3134 | srb_sg_bytecount = sge64->SgByteCount; | |
| 3135 | srb_sg_address = (void *)sge64->SgAddress; | |
| 3136 | if (sge64->SgAddress > 0xffffffffull && | |
| 3137 | (sc->flags & AAC_FLAGS_SG_64BIT) == 0) { | |
| 3138 | error = EINVAL; | |
| 3139 | goto out; | |
| 3140 | } | |
| 3141 | } | |
| 3142 | #endif | |
| 3143 | else { | |
| 3144 | error = EINVAL; | |
| 3145 | goto out; | |
| 3146 | } | |
| 3147 | ureply = (char *)arg + fibsize; | |
| 3148 | srbcmd->data_len = srb_sg_bytecount; | |
| 3149 | if (srbcmd->sg_map.SgCount == 1) | |
| 3150 | transfer_data = 1; | |
| 3151 | ||
| 3152 | cm->cm_sgtable = (struct aac_sg_table *)&srbcmd->sg_map; | |
| 3153 | if (transfer_data) { | |
| 3154 | cm->cm_datalen = srb_sg_bytecount; | |
| 3155 | cm->cm_data = kmalloc(cm->cm_datalen, M_AACBUF, M_NOWAIT); | |
| 3156 | if (cm->cm_data == NULL) { | |
| 3157 | error = ENOMEM; | |
| 3158 | goto out; | |
| 3159 | } | |
| 3160 | if (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) | |
| 3161 | cm->cm_flags |= AAC_CMD_DATAIN; | |
| 3162 | if (srbcmd->flags & AAC_SRB_FLAGS_DATA_OUT) { | |
| 3163 | cm->cm_flags |= AAC_CMD_DATAOUT; | |
| 3164 | error = copyin(srb_sg_address, cm->cm_data, | |
| 3165 | cm->cm_datalen); | |
| 3166 | if (error != 0) | |
| 3167 | goto out; | |
| 3168 | } | |
| 984263bc | 3169 | } |
| d9773475 | 3170 | |
| e9ae7f4f SW |
3171 | fib->Header.Size = sizeof(struct aac_fib_header) + |
| 3172 | sizeof(struct aac_srb); | |
| 3173 | fib->Header.XferState = | |
| 3174 | AAC_FIBSTATE_HOSTOWNED | | |
| 3175 | AAC_FIBSTATE_INITIALISED | | |
| 3176 | AAC_FIBSTATE_EMPTY | | |
| 3177 | AAC_FIBSTATE_FROMHOST | | |
| 3178 | AAC_FIBSTATE_REXPECTED | | |
| 3179 | AAC_FIBSTATE_NORM | | |
| 3180 | AAC_FIBSTATE_ASYNC | | |
| 3181 | AAC_FIBSTATE_FAST_RESPONSE; | |
| 3182 | fib->Header.Command = (sc->flags & AAC_FLAGS_SG_64BIT) != 0 ? | |
| 3183 | ScsiPortCommandU64 : ScsiPortCommand; | |
| 3184 | ||
| 3185 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); | |
| 3186 | aac_wait_command(cm); | |
| 3187 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 3188 | ||
| 3189 | if (transfer_data && (srbcmd->flags & AAC_SRB_FLAGS_DATA_IN) != 0) { | |
| 3190 | error = copyout(cm->cm_data, srb_sg_address, cm->cm_datalen); | |
| 3191 | if (error != 0) | |
| 3192 | goto out; | |
| 3193 | } | |
| 3194 | error = copyout(fib->data, ureply, sizeof(struct aac_srb_response)); | |
| 3195 | out: | |
| 3196 | if (cm != NULL) { | |
| 3197 | if (cm->cm_data != NULL) | |
| 3198 | kfree(cm->cm_data, M_AACBUF); | |
| 3199 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); | |
| 3200 | aac_release_command(cm); | |
| 3201 | lockmgr(&sc->aac_io_lock, LK_RELEASE); | |
| 3202 | } | |
| 984263bc MD |
3203 | return(error); |
| 3204 | } | |
| 3205 | ||
| e9ae7f4f SW |
3206 | static int |
| 3207 | aac_close(struct dev_close_args *ap) | |
| 3208 | { | |
| 3209 | cdev_t dev = ap->a_head.a_dev; | |
| 3210 | struct aac_softc *sc; | |
| 3211 | ||
| 3212 | sc = dev->si_drv1; | |
| 3213 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 3214 | get_mplock(); | |
| 3215 | device_unbusy(sc->aac_dev); | |
| 3216 | rel_mplock(); | |
| 3217 | ||
| 3218 | return 0; | |
| 3219 | } | |
| 3220 | ||
| 984263bc MD |
3221 | /* |
| 3222 | * Handle an AIF sent to us by the controller; queue it for later reference. | |
| 3223 | * If the queue fills up, then drop the older entries. | |
| 3224 | */ | |
| 3225 | static void | |
| 3226 | aac_handle_aif(struct aac_softc *sc, struct aac_fib *fib) | |
| 3227 | { | |
| 3228 | struct aac_aif_command *aif; | |
| 3229 | struct aac_container *co, *co_next; | |
| e9ae7f4f SW |
3230 | struct aac_fib_context *ctx; |
| 3231 | struct aac_mntinforesp *mir; | |
| 3232 | int next, current, found; | |
| 158dbeb8 | 3233 | int count = 0, added = 0, i = 0; |
| e9ae7f4f | 3234 | uint32_t channel; |
| 984263bc | 3235 | |
| e9ae7f4f | 3236 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
3237 | |
| 3238 | aif = (struct aac_aif_command*)&fib->data[0]; | |
| 3239 | aac_print_aif(sc, aif); | |
| 3240 | ||
| 3241 | /* Is it an event that we should care about? */ | |
| 3242 | switch (aif->command) { | |
| 3243 | case AifCmdEventNotify: | |
| 3244 | switch (aif->data.EN.type) { | |
| 3245 | case AifEnAddContainer: | |
| 3246 | case AifEnDeleteContainer: | |
| 3247 | /* | |
| d9773475 | 3248 | * A container was added or deleted, but the message |
| 984263bc MD |
3249 | * doesn't tell us anything else! Re-enumerate the |
| 3250 | * containers and sort things out. | |
| 3251 | */ | |
| d9773475 | 3252 | aac_alloc_sync_fib(sc, &fib); |
| 984263bc MD |
3253 | do { |
| 3254 | /* | |
| 3255 | * Ask the controller for its containers one at | |
| 3256 | * a time. | |
| 3257 | * XXX What if the controller's list changes | |
| 3258 | * midway through this enumaration? | |
| 3259 | * XXX This should be done async. | |
| 3260 | */ | |
| e9ae7f4f | 3261 | if ((mir = aac_get_container_info(sc, fib, i)) == NULL) |
| 984263bc | 3262 | continue; |
| e9ae7f4f SW |
3263 | if (i == 0) |
| 3264 | count = mir->MntRespCount; | |
| 984263bc MD |
3265 | /* |
| 3266 | * Check the container against our list. | |
| 3267 | * co->co_found was already set to 0 in a | |
| 3268 | * previous run. | |
| 3269 | */ | |
| 3270 | if ((mir->Status == ST_OK) && | |
| 3271 | (mir->MntTable[0].VolType != CT_NONE)) { | |
| 3272 | found = 0; | |
| 3273 | TAILQ_FOREACH(co, | |
| d9773475 | 3274 | &sc->aac_container_tqh, |
| 984263bc MD |
3275 | co_link) { |
| 3276 | if (co->co_mntobj.ObjectId == | |
| 3277 | mir->MntTable[0].ObjectId) { | |
| 3278 | co->co_found = 1; | |
| 3279 | found = 1; | |
| 3280 | break; | |
| 3281 | } | |
| 3282 | } | |
| 3283 | /* | |
| 3284 | * If the container matched, continue | |
| 3285 | * in the list. | |
| 3286 | */ | |
| 3287 | if (found) { | |
| 3288 | i++; | |
| 3289 | continue; | |
| 3290 | } | |
| 3291 | ||
| 3292 | /* | |
| 3293 | * This is a new container. Do all the | |
| d9773475 PA |
3294 | * appropriate things to set it up. |
| 3295 | */ | |
| 984263bc MD |
3296 | aac_add_container(sc, mir, 1); |
| 3297 | added = 1; | |
| 3298 | } | |
| 3299 | i++; | |
| 158dbeb8 | 3300 | } while ((i < count) && (i < AAC_MAX_CONTAINERS)); |
| 984263bc MD |
3301 | aac_release_sync_fib(sc); |
| 3302 | ||
| 3303 | /* | |
| 3304 | * Go through our list of containers and see which ones | |
| 3305 | * were not marked 'found'. Since the controller didn't | |
| 3306 | * list them they must have been deleted. Do the | |
| 3307 | * appropriate steps to destroy the device. Also reset | |
| 3308 | * the co->co_found field. | |
| 3309 | */ | |
| 3310 | co = TAILQ_FIRST(&sc->aac_container_tqh); | |
| 3311 | while (co != NULL) { | |
| 3312 | if (co->co_found == 0) { | |
| e9ae7f4f | 3313 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| d9773475 | 3314 | get_mplock(); |
| 984263bc MD |
3315 | device_delete_child(sc->aac_dev, |
| 3316 | co->co_disk); | |
| d9773475 | 3317 | rel_mplock(); |
| e9ae7f4f | 3318 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 984263bc | 3319 | co_next = TAILQ_NEXT(co, co_link); |
| e9ae7f4f | 3320 | lockmgr(&sc->aac_container_lock, LK_EXCLUSIVE); |
| 984263bc MD |
3321 | TAILQ_REMOVE(&sc->aac_container_tqh, co, |
| 3322 | co_link); | |
| e9ae7f4f | 3323 | lockmgr(&sc->aac_container_lock, LK_RELEASE); |
| d9773475 | 3324 | kfree(co, M_AACBUF); |
| 984263bc MD |
3325 | co = co_next; |
| 3326 | } else { | |
| 3327 | co->co_found = 0; | |
| 3328 | co = TAILQ_NEXT(co, co_link); | |
| 3329 | } | |
| 3330 | } | |
| 3331 | ||
| 3332 | /* Attach the newly created containers */ | |
| d9773475 | 3333 | if (added) { |
| e9ae7f4f | 3334 | lockmgr(&sc->aac_io_lock, LK_RELEASE); |
| d9773475 | 3335 | get_mplock(); |
| 984263bc | 3336 | bus_generic_attach(sc->aac_dev); |
| d9773475 | 3337 | rel_mplock(); |
| e9ae7f4f SW |
3338 | lockmgr(&sc->aac_io_lock, LK_EXCLUSIVE); |
| 3339 | } | |
| 3340 | ||
| 3341 | break; | |
| 3342 | ||
| 3343 | case AifEnEnclosureManagement: | |
| 3344 | switch (aif->data.EN.data.EEE.eventType) { | |
| 3345 | case AIF_EM_DRIVE_INSERTION: | |
| 3346 | case AIF_EM_DRIVE_REMOVAL: | |
| 3347 | channel = aif->data.EN.data.EEE.unitID; | |
| 3348 | if (sc->cam_rescan_cb != NULL) | |
| 3349 | sc->cam_rescan_cb(sc, | |
| 3350 | (channel >> 24) & 0xF, | |
| 3351 | (channel & 0xFFFF)); | |
| 3352 | break; | |
| d9773475 | 3353 | } |
| e9ae7f4f | 3354 | break; |
| d9773475 | 3355 | |
| e9ae7f4f SW |
3356 | case AifEnAddJBOD: |
| 3357 | case AifEnDeleteJBOD: | |
| 3358 | channel = aif->data.EN.data.ECE.container; | |
| 3359 | if (sc->cam_rescan_cb != NULL) | |
| 3360 | sc->cam_rescan_cb(sc, (channel >> 24) & 0xF, | |
| 3361 | AAC_CAM_TARGET_WILDCARD); | |
| d9773475 | 3362 | break; |
| 984263bc MD |
3363 | |
| 3364 | default: | |
| 3365 | break; | |
| 3366 | } | |
| 3367 | ||
| 3368 | default: | |
| 3369 | break; | |
| 3370 | } | |
| 3371 | ||
| 3372 | /* Copy the AIF data to the AIF queue for ioctl retrieval */ | |
| e9ae7f4f SW |
3373 | lockmgr(&sc->aac_aifq_lock, LK_EXCLUSIVE); |
| 3374 | current = sc->aifq_idx; | |
| 3375 | next = (current + 1) % AAC_AIFQ_LENGTH; | |
| 3376 | if (next == 0) | |
| 3377 | sc->aifq_filled = 1; | |
| 3378 | bcopy(fib, &sc->aac_aifq[current], sizeof(struct aac_fib)); | |
| 3379 | /* modify AIF contexts */ | |
| 3380 | if (sc->aifq_filled) { | |
| 3381 | for (ctx = sc->fibctx; ctx; ctx = ctx->next) { | |
| 3382 | if (next == ctx->ctx_idx) | |
| 3383 | ctx->ctx_wrap = 1; | |
| 3384 | else if (current == ctx->ctx_idx && ctx->ctx_wrap) | |
| 3385 | ctx->ctx_idx = next; | |
| 3386 | } | |
| 3387 | } | |
| 3388 | sc->aifq_idx = next; | |
| 3389 | /* On the off chance that someone is sleeping for an aif... */ | |
| 3390 | if (sc->aac_state & AAC_STATE_AIF_SLEEPER) | |
| 3391 | wakeup(sc->aac_aifq); | |
| 3392 | /* token may have been lost */ | |
| 3393 | /* Wakeup any poll()ers */ | |
| 3394 | KNOTE(&sc->rcv_kq.ki_note, 0); | |
| 3395 | /* token may have been lost */ | |
| 3396 | lockmgr(&sc->aac_aifq_lock, LK_RELEASE); | |
| 984263bc MD |
3397 | |
| 3398 | return; | |
| 3399 | } | |
| 3400 | ||
| 3401 | /* | |
| 3402 | * Return the Revision of the driver to userspace and check to see if the | |
| 3403 | * userspace app is possibly compatible. This is extremely bogus since | |
| 3404 | * our driver doesn't follow Adaptec's versioning system. Cheat by just | |
| 3405 | * returning what the card reported. | |
| 3406 | */ | |
| 3407 | static int | |
| 3408 | aac_rev_check(struct aac_softc *sc, caddr_t udata) | |
| 3409 | { | |
| 3410 | struct aac_rev_check rev_check; | |
| 3411 | struct aac_rev_check_resp rev_check_resp; | |
| 3412 | int error = 0; | |
| 3413 | ||
| e9ae7f4f | 3414 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
3415 | |
| 3416 | /* | |
| 3417 | * Copyin the revision struct from userspace | |
| 3418 | */ | |
| 3419 | if ((error = copyin(udata, (caddr_t)&rev_check, | |
| 3420 | sizeof(struct aac_rev_check))) != 0) { | |
| 3421 | return error; | |
| 3422 | } | |
| 3423 | ||
| e9ae7f4f | 3424 | fwprintf(sc, HBA_FLAGS_DBG_IOCTL_COMMANDS_B, "Userland revision= %d\n", |
| 984263bc MD |
3425 | rev_check.callingRevision.buildNumber); |
| 3426 | ||
| 3427 | /* | |
| 3428 | * Doctor up the response struct. | |
| 3429 | */ | |
| 3430 | rev_check_resp.possiblyCompatible = 1; | |
| e9ae7f4f SW |
3431 | rev_check_resp.adapterSWRevision.external.comp.major = |
| 3432 | AAC_DRIVER_MAJOR_VERSION; | |
| 3433 | rev_check_resp.adapterSWRevision.external.comp.minor = | |
| 3434 | AAC_DRIVER_MINOR_VERSION; | |
| 3435 | rev_check_resp.adapterSWRevision.external.comp.type = | |
| 3436 | AAC_DRIVER_TYPE; | |
| 3437 | rev_check_resp.adapterSWRevision.external.comp.dash = | |
| 3438 | AAC_DRIVER_BUGFIX_LEVEL; | |
| 984263bc | 3439 | rev_check_resp.adapterSWRevision.buildNumber = |
| e9ae7f4f | 3440 | AAC_DRIVER_BUILD; |
| 984263bc MD |
3441 | |
| 3442 | return(copyout((caddr_t)&rev_check_resp, udata, | |
| 3443 | sizeof(struct aac_rev_check_resp))); | |
| 3444 | } | |
| 3445 | ||
| 3446 | /* | |
| e9ae7f4f SW |
3447 | * Pass the fib context to the caller |
| 3448 | */ | |
| 3449 | static int | |
| 3450 | aac_open_aif(struct aac_softc *sc, caddr_t arg) | |
| 3451 | { | |
| 3452 | struct aac_fib_context *fibctx, *ctx; | |
| 3453 | int error = 0; | |
| 3454 | ||
| 3455 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 3456 | ||
| 3457 | fibctx = kmalloc(sizeof(struct aac_fib_context), M_AACBUF, M_NOWAIT|M_ZERO); | |
| 3458 | if (fibctx == NULL) | |
| 3459 | return (ENOMEM); | |
| 3460 | ||
| 3461 | lockmgr(&sc->aac_aifq_lock, LK_EXCLUSIVE); | |
| 3462 | /* all elements are already 0, add to queue */ | |
| 3463 | if (sc->fibctx == NULL) | |
| 3464 | sc->fibctx = fibctx; | |
| 3465 | else { | |
| 3466 | for (ctx = sc->fibctx; ctx->next; ctx = ctx->next) | |
| 3467 | ; | |
| 3468 | ctx->next = fibctx; | |
| 3469 | fibctx->prev = ctx; | |
| 3470 | } | |
| 3471 | ||
| 3472 | /* evaluate unique value */ | |
| 3473 | fibctx->unique = (*(u_int32_t *)&fibctx & 0xffffffff); | |
| 3474 | ctx = sc->fibctx; | |
| 3475 | while (ctx != fibctx) { | |
| 3476 | if (ctx->unique == fibctx->unique) { | |
| 3477 | fibctx->unique++; | |
| 3478 | ctx = sc->fibctx; | |
| 3479 | } else { | |
| 3480 | ctx = ctx->next; | |
| 3481 | } | |
| 3482 | } | |
| 3483 | lockmgr(&sc->aac_aifq_lock, LK_RELEASE); | |
| 3484 | ||
| 3485 | error = copyout(&fibctx->unique, (void *)arg, sizeof(u_int32_t)); | |
| 3486 | if (error) | |
| 3487 | aac_close_aif(sc, (caddr_t)ctx); | |
| 3488 | return error; | |
| 3489 | } | |
| 3490 | ||
| 3491 | /* | |
| 3492 | * Close the caller's fib context | |
| 3493 | */ | |
| 3494 | static int | |
| 3495 | aac_close_aif(struct aac_softc *sc, caddr_t arg) | |
| 3496 | { | |
| 3497 | struct aac_fib_context *ctx; | |
| 3498 | ||
| 3499 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); | |
| 3500 | ||
| 3501 | lockmgr(&sc->aac_aifq_lock, LK_EXCLUSIVE); | |
| 3502 | for (ctx = sc->fibctx; ctx; ctx = ctx->next) { | |
| 3503 | if (ctx->unique == *(uint32_t *)&arg) { | |
| 3504 | if (ctx == sc->fibctx) | |
| 3505 | sc->fibctx = NULL; | |
| 3506 | else { | |
| 3507 | ctx->prev->next = ctx->next; | |
| 3508 | if (ctx->next) | |
| 3509 | ctx->next->prev = ctx->prev; | |
| 3510 | } | |
| 3511 | break; | |
| 3512 | } | |
| 3513 | } | |
| 3514 | lockmgr(&sc->aac_aifq_lock, LK_RELEASE); | |
| 3515 | if (ctx) | |
| 3516 | kfree(ctx, M_AACBUF); | |
| 3517 | ||
| 3518 | return 0; | |
| 3519 | } | |
| 3520 | ||
| 3521 | /* | |
| 984263bc MD |
3522 | * Pass the caller the next AIF in their queue |
| 3523 | */ | |
| 3524 | static int | |
| 3525 | aac_getnext_aif(struct aac_softc *sc, caddr_t arg) | |
| 3526 | { | |
| 3527 | struct get_adapter_fib_ioctl agf; | |
| e9ae7f4f | 3528 | struct aac_fib_context *ctx; |
| 7f2216bc | 3529 | int error; |
| 984263bc | 3530 | |
| e9ae7f4f | 3531 | fwprintf(sc, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, ""); |
| 984263bc MD |
3532 | |
| 3533 | if ((error = copyin(arg, &agf, sizeof(agf))) == 0) { | |
| e9ae7f4f SW |
3534 | for (ctx = sc->fibctx; ctx; ctx = ctx->next) { |