1edc6143bSDavid Rhodus /*-
2edc6143bSDavid Rhodus * Written by: David Jeffery
3edc6143bSDavid Rhodus * Copyright (c) 2002 Adaptec Inc.
4edc6143bSDavid Rhodus * All rights reserved.
5edc6143bSDavid Rhodus *
6edc6143bSDavid Rhodus * Redistribution and use in source and binary forms, with or without
7edc6143bSDavid Rhodus * modification, are permitted provided that the following conditions
8edc6143bSDavid Rhodus * are met:
9edc6143bSDavid Rhodus * 1. Redistributions of source code must retain the above copyright
10edc6143bSDavid Rhodus * notice, this list of conditions and the following disclaimer.
11edc6143bSDavid Rhodus * 2. Redistributions in binary form must reproduce the above copyright
12edc6143bSDavid Rhodus * notice, this list of conditions and the following disclaimer in the
13edc6143bSDavid Rhodus * documentation and/or other materials provided with the distribution.
14edc6143bSDavid Rhodus *
15edc6143bSDavid Rhodus * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16edc6143bSDavid Rhodus * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17edc6143bSDavid Rhodus * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18edc6143bSDavid Rhodus * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19edc6143bSDavid Rhodus * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20edc6143bSDavid Rhodus * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21edc6143bSDavid Rhodus * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22edc6143bSDavid Rhodus * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23edc6143bSDavid Rhodus * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24edc6143bSDavid Rhodus * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25edc6143bSDavid Rhodus * SUCH DAMAGE.
26edc6143bSDavid Rhodus *
27c27aad16SJoerg Sonnenberger * $FreeBSD: src/sys/dev/ips/ips_commands.c,v 1.10 2004/05/30 04:01:29 scottl Exp $
28edc6143bSDavid Rhodus */
29edc6143bSDavid Rhodus
3081b5c339SMatthew Dillon #include <sys/devicestat.h>
31ac8b35f8SYONETANI Tomokazu #include <sys/sysctl.h>
32edc6143bSDavid Rhodus #include <dev/raid/ips/ips.h>
3381b5c339SMatthew Dillon #include <dev/raid/ips/ips_disk.h>
34edc6143bSDavid Rhodus
35ac8b35f8SYONETANI Tomokazu static int ips_debug_ignore_flush_cmd;
36ac8b35f8SYONETANI Tomokazu TUNABLE_INT("debug.ips.ignore_flush_cmd", &ips_debug_ignore_flush_cmd);
37ac8b35f8SYONETANI Tomokazu SYSCTL_NODE(_debug, OID_AUTO, ips, CTLFLAG_RD, 0, "");
38ac8b35f8SYONETANI Tomokazu SYSCTL_INT(_debug_ips, OID_AUTO, ignore_flush_cmd, CTLFLAG_RW,
39ac8b35f8SYONETANI Tomokazu &ips_debug_ignore_flush_cmd, 0,
40ac8b35f8SYONETANI Tomokazu "Do not issue IPS_CACHE_FLUSH_CMD on BUF_CMD_FLUSH");
41ac8b35f8SYONETANI Tomokazu
424751a114SMatthew Dillon int
ips_timed_wait(ips_command_t * command,const char * id,int timo)434751a114SMatthew Dillon ips_timed_wait(ips_command_t *command, const char *id, int timo)
444751a114SMatthew Dillon {
454751a114SMatthew Dillon int error = 0;
464751a114SMatthew Dillon
474751a114SMatthew Dillon while (command->completed == 0) {
484751a114SMatthew Dillon crit_enter();
494751a114SMatthew Dillon if (command->completed == 0)
504751a114SMatthew Dillon error = tsleep(&command->completed, 0, id, timo);
514751a114SMatthew Dillon crit_exit();
524751a114SMatthew Dillon if (error == EWOULDBLOCK) {
534751a114SMatthew Dillon error = ETIMEDOUT;
544751a114SMatthew Dillon break;
554751a114SMatthew Dillon }
564751a114SMatthew Dillon }
574751a114SMatthew Dillon return(error);
584751a114SMatthew Dillon }
594751a114SMatthew Dillon
60edc6143bSDavid Rhodus /*
61edc6143bSDavid Rhodus * This is an interrupt callback. It is called from
62edc6143bSDavid Rhodus * interrupt context when the adapter has completed the
634751a114SMatthew Dillon * command, and wakes up anyone waiting on the command.
64edc6143bSDavid Rhodus */
65edc6143bSDavid Rhodus static void
ips_wakeup_callback(ips_command_t * command)66edc6143bSDavid Rhodus ips_wakeup_callback(ips_command_t *command)
67edc6143bSDavid Rhodus {
68edc6143bSDavid Rhodus bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
69edc6143bSDavid Rhodus BUS_DMASYNC_POSTWRITE);
704751a114SMatthew Dillon command->completed = 1;
714751a114SMatthew Dillon wakeup(&command->completed);
72edc6143bSDavid Rhodus }
73ad57418eSJoerg Sonnenberger
74ad57418eSJoerg Sonnenberger /*
75ad57418eSJoerg Sonnenberger * Below are a series of functions for sending an IO request
76edc6143bSDavid Rhodus * to the adapter. The flow order is: start, send, callback, finish.
77edc6143bSDavid Rhodus * The caller must have already assembled an iorequest struct to hold
78ad57418eSJoerg Sonnenberger * the details of the IO request.
79ad57418eSJoerg Sonnenberger */
80ad57418eSJoerg Sonnenberger static void
ips_io_request_finish(ips_command_t * command)81ad57418eSJoerg Sonnenberger ips_io_request_finish(ips_command_t *command)
82edc6143bSDavid Rhodus {
8381b5c339SMatthew Dillon struct bio *bio = command->arg;
84edc6143bSDavid Rhodus
8581b5c339SMatthew Dillon if (ips_read_request(bio)) {
86edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
87edc6143bSDavid Rhodus BUS_DMASYNC_POSTREAD);
88edc6143bSDavid Rhodus } else {
89edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
90edc6143bSDavid Rhodus BUS_DMASYNC_POSTWRITE);
91edc6143bSDavid Rhodus }
92edc6143bSDavid Rhodus bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
93edc6143bSDavid Rhodus if (COMMAND_ERROR(&command->status)) {
9481b5c339SMatthew Dillon bio->bio_buf->b_flags |=B_ERROR;
9581b5c339SMatthew Dillon bio->bio_buf->b_error = EIO;
96edc6143bSDavid Rhodus }
97edc6143bSDavid Rhodus ips_insert_free_cmd(command->sc, command);
9881b5c339SMatthew Dillon ipsd_finish(bio);
99edc6143bSDavid Rhodus }
100edc6143bSDavid Rhodus
101edc6143bSDavid Rhodus static void
ips_io_request_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)102edc6143bSDavid Rhodus ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
103edc6143bSDavid Rhodus int error)
104edc6143bSDavid Rhodus {
105edc6143bSDavid Rhodus ips_softc_t *sc;
106edc6143bSDavid Rhodus ips_command_t *command = cmdptr;
107edc6143bSDavid Rhodus ips_sg_element_t *sg_list;
108edc6143bSDavid Rhodus ips_io_cmd *command_struct;
10981b5c339SMatthew Dillon struct bio *bio = command->arg;
11081b5c339SMatthew Dillon struct buf *bp = bio->bio_buf;
11181b5c339SMatthew Dillon ipsdisk_softc_t *dsc;
112edc6143bSDavid Rhodus int i, length = 0;
113edc6143bSDavid Rhodus u_int8_t cmdtype;
114edc6143bSDavid Rhodus
115edc6143bSDavid Rhodus sc = command->sc;
116edc6143bSDavid Rhodus if (error) {
117*e3869ec7SSascha Wildner kprintf("ips: error = %d in ips_sg_request_callback\n", error);
118edc6143bSDavid Rhodus bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
11981b5c339SMatthew Dillon bp->b_flags |= B_ERROR;
12081b5c339SMatthew Dillon bp->b_error = ENOMEM;
121edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
12281b5c339SMatthew Dillon ipsd_finish(bio);
123edc6143bSDavid Rhodus return;
124edc6143bSDavid Rhodus }
12581b5c339SMatthew Dillon dsc = bio->bio_driver_info;
126edc6143bSDavid Rhodus command_struct = (ips_io_cmd *)command->command_buffer;
127edc6143bSDavid Rhodus command_struct->id = command->id;
12881b5c339SMatthew Dillon command_struct->drivenum = dsc->sc->drives[dsc->disk_number].drivenum;
12981b5c339SMatthew Dillon
130edc6143bSDavid Rhodus if (segnum != 1) {
13181b5c339SMatthew Dillon if (ips_read_request(bio))
132edc6143bSDavid Rhodus cmdtype = IPS_SG_READ_CMD;
133edc6143bSDavid Rhodus else
134edc6143bSDavid Rhodus cmdtype = IPS_SG_WRITE_CMD;
135edc6143bSDavid Rhodus command_struct->segnum = segnum;
136edc6143bSDavid Rhodus sg_list = (ips_sg_element_t *)((u_int8_t *)
137edc6143bSDavid Rhodus command->command_buffer + IPS_COMMAND_LEN);
138edc6143bSDavid Rhodus for (i = 0; i < segnum; i++) {
139edc6143bSDavid Rhodus sg_list[i].addr = segments[i].ds_addr;
140edc6143bSDavid Rhodus sg_list[i].len = segments[i].ds_len;
141edc6143bSDavid Rhodus length += segments[i].ds_len;
142edc6143bSDavid Rhodus }
143edc6143bSDavid Rhodus command_struct->buffaddr =
144edc6143bSDavid Rhodus (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
145edc6143bSDavid Rhodus } else {
14681b5c339SMatthew Dillon if (ips_read_request(bio))
147edc6143bSDavid Rhodus cmdtype = IPS_READ_CMD;
148edc6143bSDavid Rhodus else
149edc6143bSDavid Rhodus cmdtype = IPS_WRITE_CMD;
150edc6143bSDavid Rhodus command_struct->buffaddr = segments[0].ds_addr;
151edc6143bSDavid Rhodus length = segments[0].ds_len;
152edc6143bSDavid Rhodus }
153edc6143bSDavid Rhodus command_struct->command = cmdtype;
15454078292SMatthew Dillon command_struct->lba = bio->bio_offset / IPS_BLKSIZE;
155edc6143bSDavid Rhodus length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
156edc6143bSDavid Rhodus command_struct->length = length;
157edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
158edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
15981b5c339SMatthew Dillon if (ips_read_request(bio)) {
160edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
161edc6143bSDavid Rhodus BUS_DMASYNC_PREREAD);
162edc6143bSDavid Rhodus } else {
163edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
164edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
165edc6143bSDavid Rhodus }
166edc6143bSDavid Rhodus PRINTF(10, "ips test: command id: %d segments: %d "
167edc6143bSDavid Rhodus "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
16854078292SMatthew Dillon bio->bio_offset / IPS_BLKSIZE,
169edc6143bSDavid Rhodus length, segments[0].ds_len);
170edc6143bSDavid Rhodus
171edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
172edc6143bSDavid Rhodus return;
173edc6143bSDavid Rhodus }
174edc6143bSDavid Rhodus
175ac8b35f8SYONETANI Tomokazu static void
ips_flush_request_finish(ips_command_t * command)176ac8b35f8SYONETANI Tomokazu ips_flush_request_finish(ips_command_t *command)
177ac8b35f8SYONETANI Tomokazu {
178ac8b35f8SYONETANI Tomokazu ips_generic_cmd *gencmd = command->command_buffer;
179ac8b35f8SYONETANI Tomokazu struct bio *bio = command->arg;
180ac8b35f8SYONETANI Tomokazu
181ac8b35f8SYONETANI Tomokazu if (COMMAND_ERROR(&command->status)) {
182ac8b35f8SYONETANI Tomokazu device_printf(command->sc->dev,
183ac8b35f8SYONETANI Tomokazu "cmd=0x%x,st=0x%x,est=0x%x\n",
184ac8b35f8SYONETANI Tomokazu gencmd->command,
185ac8b35f8SYONETANI Tomokazu command->status.fields.basic_status,
186ac8b35f8SYONETANI Tomokazu command->status.fields.extended_status);
187ac8b35f8SYONETANI Tomokazu
188ac8b35f8SYONETANI Tomokazu bio->bio_buf->b_flags |= B_ERROR;
189ac8b35f8SYONETANI Tomokazu bio->bio_buf->b_error = EIO;
190ac8b35f8SYONETANI Tomokazu }
191ac8b35f8SYONETANI Tomokazu ips_insert_free_cmd(command->sc, command);
192ac8b35f8SYONETANI Tomokazu ipsd_finish(bio);
193ac8b35f8SYONETANI Tomokazu }
194ac8b35f8SYONETANI Tomokazu
195ac8b35f8SYONETANI Tomokazu static int
ips_send_flush_request(ips_command_t * command,struct bio * bio)196ac8b35f8SYONETANI Tomokazu ips_send_flush_request(ips_command_t *command, struct bio *bio)
197ac8b35f8SYONETANI Tomokazu {
198ac8b35f8SYONETANI Tomokazu command->arg = bio;
199ac8b35f8SYONETANI Tomokazu ips_generic_cmd *flush_cmd;
200ac8b35f8SYONETANI Tomokazu ips_softc_t *sc = command->sc;
201ac8b35f8SYONETANI Tomokazu
202ac8b35f8SYONETANI Tomokazu if (!ips_debug_ignore_flush_cmd) {
203ac8b35f8SYONETANI Tomokazu ips_insert_free_cmd(sc, command);
204ac8b35f8SYONETANI Tomokazu ipsd_finish(bio);
205ac8b35f8SYONETANI Tomokazu return 0;
206ac8b35f8SYONETANI Tomokazu }
207ac8b35f8SYONETANI Tomokazu
208ac8b35f8SYONETANI Tomokazu command->callback = ips_flush_request_finish;
209ac8b35f8SYONETANI Tomokazu flush_cmd = command->command_buffer;
210ac8b35f8SYONETANI Tomokazu flush_cmd->command = IPS_CACHE_FLUSH_CMD;
211ac8b35f8SYONETANI Tomokazu flush_cmd->id = command->id;
212ac8b35f8SYONETANI Tomokazu flush_cmd->drivenum = 0;
213ac8b35f8SYONETANI Tomokazu flush_cmd->buffaddr = 0;
214ac8b35f8SYONETANI Tomokazu flush_cmd->lba = 0;
215ac8b35f8SYONETANI Tomokazu bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
216ac8b35f8SYONETANI Tomokazu BUS_DMASYNC_PREWRITE);
217ac8b35f8SYONETANI Tomokazu
218ac8b35f8SYONETANI Tomokazu sc->ips_issue_cmd(command);
219ac8b35f8SYONETANI Tomokazu return 0;
220ac8b35f8SYONETANI Tomokazu }
221ac8b35f8SYONETANI Tomokazu
222ac8b35f8SYONETANI Tomokazu
223edc6143bSDavid Rhodus static int
ips_send_io_request(ips_command_t * command,struct bio * bio)22481b5c339SMatthew Dillon ips_send_io_request(ips_command_t *command, struct bio *bio)
225edc6143bSDavid Rhodus {
22681b5c339SMatthew Dillon struct buf *bp = bio->bio_buf;
22781b5c339SMatthew Dillon
228edc6143bSDavid Rhodus command->callback = ips_io_request_finish;
22981b5c339SMatthew Dillon command->arg = bio;
23081b5c339SMatthew Dillon PRINTF(10, "ips test: : bcount %ld\n", bp->b_bcount);
231edc6143bSDavid Rhodus bus_dmamap_load(command->data_dmatag, command->data_dmamap,
23281b5c339SMatthew Dillon bp->b_data, bp->b_bcount,
233edc6143bSDavid Rhodus ips_io_request_callback, command, 0);
234edc6143bSDavid Rhodus return 0;
235edc6143bSDavid Rhodus }
236edc6143bSDavid Rhodus
237edc6143bSDavid Rhodus void
ips_start_io_request(ips_softc_t * sc)2384751a114SMatthew Dillon ips_start_io_request(ips_softc_t *sc)
239edc6143bSDavid Rhodus {
2404751a114SMatthew Dillon ips_command_t *command;
24181b5c339SMatthew Dillon struct bio *bio;
2424751a114SMatthew Dillon
24381b5c339SMatthew Dillon bio = bioq_first(&sc->bio_queue);
24481b5c339SMatthew Dillon if (bio == NULL)
245edc6143bSDavid Rhodus return;
2464751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, 0) != 0)
247edc6143bSDavid Rhodus return;
24881b5c339SMatthew Dillon bioq_remove(&sc->bio_queue, bio);
249ac8b35f8SYONETANI Tomokazu if (bio->bio_buf->b_cmd == BUF_CMD_FLUSH)
250ac8b35f8SYONETANI Tomokazu ips_send_flush_request(command, bio);
251ac8b35f8SYONETANI Tomokazu else
25281b5c339SMatthew Dillon ips_send_io_request(command, bio);
253edc6143bSDavid Rhodus }
254edc6143bSDavid Rhodus
255edc6143bSDavid Rhodus /*
256edc6143bSDavid Rhodus * Below are a series of functions for sending an adapter info request
257edc6143bSDavid Rhodus * to the adapter. The flow order is: get, send, callback. It uses
258edc6143bSDavid Rhodus * the generic finish callback at the top of this file.
259edc6143bSDavid Rhodus * This can be used to get configuration/status info from the card
260edc6143bSDavid Rhodus */
261edc6143bSDavid Rhodus static void
ips_adapter_info_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)262edc6143bSDavid Rhodus ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum,
263edc6143bSDavid Rhodus int error)
264edc6143bSDavid Rhodus {
265edc6143bSDavid Rhodus ips_softc_t *sc;
266edc6143bSDavid Rhodus ips_command_t *command = cmdptr;
267edc6143bSDavid Rhodus ips_adapter_info_cmd *command_struct;
268edc6143bSDavid Rhodus sc = command->sc;
269edc6143bSDavid Rhodus if (error) {
2704751a114SMatthew Dillon command->status.value = IPS_ERROR_STATUS; /* a lovely error value */
271edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
272*e3869ec7SSascha Wildner kprintf("ips: error = %d in ips_get_adapter_info\n", error);
273edc6143bSDavid Rhodus return;
274edc6143bSDavid Rhodus }
275edc6143bSDavid Rhodus command_struct = (ips_adapter_info_cmd *)command->command_buffer;
276edc6143bSDavid Rhodus command_struct->command = IPS_ADAPTER_INFO_CMD;
277edc6143bSDavid Rhodus command_struct->id = command->id;
278edc6143bSDavid Rhodus command_struct->buffaddr = segments[0].ds_addr;
279edc6143bSDavid Rhodus
280edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
281edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
282edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
283edc6143bSDavid Rhodus BUS_DMASYNC_PREREAD);
284edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
285edc6143bSDavid Rhodus }
286edc6143bSDavid Rhodus
287edc6143bSDavid Rhodus static int
ips_send_adapter_info_cmd(ips_command_t * command)288edc6143bSDavid Rhodus ips_send_adapter_info_cmd(ips_command_t *command)
289edc6143bSDavid Rhodus {
290edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
291edc6143bSDavid Rhodus int error = 0;
292edc6143bSDavid Rhodus
293edc6143bSDavid Rhodus if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
294edc6143bSDavid Rhodus /* alignemnt */ 1,
295edc6143bSDavid Rhodus /* boundary */ 0,
296edc6143bSDavid Rhodus /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
297edc6143bSDavid Rhodus /* highaddr */ BUS_SPACE_MAXADDR,
298edc6143bSDavid Rhodus /* maxsize */ IPS_ADAPTER_INFO_LEN,
299edc6143bSDavid Rhodus /* numsegs */ 1,
300edc6143bSDavid Rhodus /* maxsegsize*/ IPS_ADAPTER_INFO_LEN,
301edc6143bSDavid Rhodus /* flags */ 0,
302edc6143bSDavid Rhodus &command->data_dmatag) != 0) {
303*e3869ec7SSascha Wildner kprintf("ips: can't alloc dma tag for adapter status\n");
304edc6143bSDavid Rhodus error = ENOMEM;
305edc6143bSDavid Rhodus goto exit;
306edc6143bSDavid Rhodus }
307edc6143bSDavid Rhodus if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
308edc6143bSDavid Rhodus BUS_DMA_NOWAIT, &command->data_dmamap)) {
309edc6143bSDavid Rhodus error = ENOMEM;
310edc6143bSDavid Rhodus goto exit;
311edc6143bSDavid Rhodus }
312edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
313edc6143bSDavid Rhodus bus_dmamap_load(command->data_dmatag, command->data_dmamap,
314edc6143bSDavid Rhodus command->data_buffer, IPS_ADAPTER_INFO_LEN,
315edc6143bSDavid Rhodus ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
3164751a114SMatthew Dillon if ((command->status.value == IPS_ERROR_STATUS) ||
3174751a114SMatthew Dillon ips_timed_wait(command, "ips", 30 * hz) != 0)
318edc6143bSDavid Rhodus error = ETIMEDOUT;
319edc6143bSDavid Rhodus if (error == 0) {
320edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
321edc6143bSDavid Rhodus BUS_DMASYNC_POSTREAD);
322edc6143bSDavid Rhodus memcpy(&(sc->adapter_info), command->data_buffer,
323edc6143bSDavid Rhodus IPS_ADAPTER_INFO_LEN);
324edc6143bSDavid Rhodus }
325edc6143bSDavid Rhodus bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
326edc6143bSDavid Rhodus exit:
327edc6143bSDavid Rhodus /* I suppose I should clean up my memory allocations */
328edc6143bSDavid Rhodus bus_dmamem_free(command->data_dmatag, command->data_buffer,
329edc6143bSDavid Rhodus command->data_dmamap);
330edc6143bSDavid Rhodus bus_dma_tag_destroy(command->data_dmatag);
331edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
332edc6143bSDavid Rhodus return error;
333edc6143bSDavid Rhodus }
334edc6143bSDavid Rhodus
335edc6143bSDavid Rhodus int
ips_get_adapter_info(ips_softc_t * sc)336edc6143bSDavid Rhodus ips_get_adapter_info(ips_softc_t *sc)
337edc6143bSDavid Rhodus {
3384751a114SMatthew Dillon ips_command_t *command;
339edc6143bSDavid Rhodus int error = 0;
340edc6143bSDavid Rhodus
3414751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
342edc6143bSDavid Rhodus device_printf(sc->dev, "unable to get adapter configuration\n");
343edc6143bSDavid Rhodus return ENXIO;
344edc6143bSDavid Rhodus }
3454751a114SMatthew Dillon ips_send_adapter_info_cmd(command);
3464751a114SMatthew Dillon if (COMMAND_ERROR(&command->status))
347edc6143bSDavid Rhodus error = ENXIO;
348edc6143bSDavid Rhodus return error;
349edc6143bSDavid Rhodus }
350edc6143bSDavid Rhodus
351edc6143bSDavid Rhodus /*
352edc6143bSDavid Rhodus * Below are a series of functions for sending a drive info request
353edc6143bSDavid Rhodus * to the adapter. The flow order is: get, send, callback. It uses
354edc6143bSDavid Rhodus * the generic finish callback at the top of this file.
355edc6143bSDavid Rhodus * This can be used to get drive status info from the card
356edc6143bSDavid Rhodus */
357edc6143bSDavid Rhodus static void
ips_drive_info_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)358edc6143bSDavid Rhodus ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
359edc6143bSDavid Rhodus int error)
360edc6143bSDavid Rhodus {
361edc6143bSDavid Rhodus ips_softc_t *sc;
362edc6143bSDavid Rhodus ips_command_t *command = cmdptr;
363edc6143bSDavid Rhodus ips_drive_cmd *command_struct;
364edc6143bSDavid Rhodus
365edc6143bSDavid Rhodus sc = command->sc;
366edc6143bSDavid Rhodus if (error) {
367edc6143bSDavid Rhodus
3684751a114SMatthew Dillon command->status.value = IPS_ERROR_STATUS;
369edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
370*e3869ec7SSascha Wildner kprintf("ips: error = %d in ips_get_drive_info\n", error);
371edc6143bSDavid Rhodus return;
372edc6143bSDavid Rhodus }
373edc6143bSDavid Rhodus command_struct = (ips_drive_cmd *)command->command_buffer;
374edc6143bSDavid Rhodus command_struct->command = IPS_DRIVE_INFO_CMD;
375edc6143bSDavid Rhodus command_struct->id = command->id;
376edc6143bSDavid Rhodus command_struct->buffaddr = segments[0].ds_addr;
377edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
378edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
379edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
380edc6143bSDavid Rhodus BUS_DMASYNC_PREREAD);
381edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
382edc6143bSDavid Rhodus }
383edc6143bSDavid Rhodus
384edc6143bSDavid Rhodus static int
ips_send_drive_info_cmd(ips_command_t * command)385edc6143bSDavid Rhodus ips_send_drive_info_cmd(ips_command_t *command)
386edc6143bSDavid Rhodus {
387edc6143bSDavid Rhodus int error = 0;
388edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
389edc6143bSDavid Rhodus ips_drive_info_t *driveinfo;
390edc6143bSDavid Rhodus
391edc6143bSDavid Rhodus if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
392edc6143bSDavid Rhodus /* alignemnt */ 1,
393edc6143bSDavid Rhodus /* boundary */ 0,
394edc6143bSDavid Rhodus /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
395edc6143bSDavid Rhodus /* highaddr */ BUS_SPACE_MAXADDR,
396edc6143bSDavid Rhodus /* maxsize */ IPS_DRIVE_INFO_LEN,
397edc6143bSDavid Rhodus /* numsegs */ 1,
398edc6143bSDavid Rhodus /* maxsegsize*/ IPS_DRIVE_INFO_LEN,
399edc6143bSDavid Rhodus /* flags */ 0,
400edc6143bSDavid Rhodus &command->data_dmatag) != 0) {
401*e3869ec7SSascha Wildner kprintf("ips: can't alloc dma tag for drive status\n");
402edc6143bSDavid Rhodus error = ENOMEM;
403edc6143bSDavid Rhodus goto exit;
404edc6143bSDavid Rhodus }
405edc6143bSDavid Rhodus if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
406edc6143bSDavid Rhodus BUS_DMA_NOWAIT, &command->data_dmamap)) {
407edc6143bSDavid Rhodus error = ENOMEM;
408edc6143bSDavid Rhodus goto exit;
409edc6143bSDavid Rhodus }
410edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
411edc6143bSDavid Rhodus bus_dmamap_load(command->data_dmatag, command->data_dmamap,
412edc6143bSDavid Rhodus command->data_buffer,IPS_DRIVE_INFO_LEN,
413edc6143bSDavid Rhodus ips_drive_info_callback, command, BUS_DMA_NOWAIT);
4144751a114SMatthew Dillon if ((command->status.value == IPS_ERROR_STATUS) ||
4154751a114SMatthew Dillon ips_timed_wait(command, "ips", 10 * hz) != 0)
416edc6143bSDavid Rhodus error = ETIMEDOUT;
417edc6143bSDavid Rhodus
418edc6143bSDavid Rhodus if (error == 0) {
419edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
420edc6143bSDavid Rhodus BUS_DMASYNC_POSTREAD);
421edc6143bSDavid Rhodus driveinfo = command->data_buffer;
422edc6143bSDavid Rhodus memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
423edc6143bSDavid Rhodus sc->drivecount = driveinfo->drivecount;
424edc6143bSDavid Rhodus device_printf(sc->dev, "logical drives: %d\n", sc->drivecount);
425edc6143bSDavid Rhodus }
426edc6143bSDavid Rhodus bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
427edc6143bSDavid Rhodus exit:
428edc6143bSDavid Rhodus /* I suppose I should clean up my memory allocations */
429edc6143bSDavid Rhodus bus_dmamem_free(command->data_dmatag, command->data_buffer,
430edc6143bSDavid Rhodus command->data_dmamap);
431edc6143bSDavid Rhodus bus_dma_tag_destroy(command->data_dmatag);
432edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
433edc6143bSDavid Rhodus return error;
434edc6143bSDavid Rhodus }
4354751a114SMatthew Dillon
436edc6143bSDavid Rhodus int
ips_get_drive_info(ips_softc_t * sc)437edc6143bSDavid Rhodus ips_get_drive_info(ips_softc_t *sc)
438edc6143bSDavid Rhodus {
439edc6143bSDavid Rhodus int error = 0;
4404751a114SMatthew Dillon ips_command_t *command;
441edc6143bSDavid Rhodus
4424751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
443edc6143bSDavid Rhodus device_printf(sc->dev, "unable to get drive configuration\n");
444edc6143bSDavid Rhodus return ENXIO;
445edc6143bSDavid Rhodus }
4464751a114SMatthew Dillon ips_send_drive_info_cmd(command);
4474751a114SMatthew Dillon if (COMMAND_ERROR(&command->status))
448edc6143bSDavid Rhodus error = ENXIO;
449edc6143bSDavid Rhodus return error;
450edc6143bSDavid Rhodus }
451edc6143bSDavid Rhodus
452edc6143bSDavid Rhodus /*
453edc6143bSDavid Rhodus * Below is a pair of functions for making sure data is safely
454edc6143bSDavid Rhodus * on disk by flushing the adapter's cache.
455edc6143bSDavid Rhodus */
456edc6143bSDavid Rhodus static int
ips_send_flush_cache_cmd(ips_command_t * command)457edc6143bSDavid Rhodus ips_send_flush_cache_cmd(ips_command_t *command)
458edc6143bSDavid Rhodus {
459edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
460edc6143bSDavid Rhodus ips_generic_cmd *command_struct;
461edc6143bSDavid Rhodus
462edc6143bSDavid Rhodus PRINTF(10,"ips test: got a command, building flush command\n");
463edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
464edc6143bSDavid Rhodus command_struct = (ips_generic_cmd *)command->command_buffer;
465edc6143bSDavid Rhodus command_struct->command = IPS_CACHE_FLUSH_CMD;
466edc6143bSDavid Rhodus command_struct->id = command->id;
467edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
468edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
469edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
4704751a114SMatthew Dillon if (command->status.value != IPS_ERROR_STATUS)
4714751a114SMatthew Dillon ips_timed_wait(command, "flush2", 0);
472edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
473edc6143bSDavid Rhodus return 0;
474edc6143bSDavid Rhodus }
475edc6143bSDavid Rhodus
476edc6143bSDavid Rhodus int
ips_flush_cache(ips_softc_t * sc)477edc6143bSDavid Rhodus ips_flush_cache(ips_softc_t *sc)
478edc6143bSDavid Rhodus {
4794751a114SMatthew Dillon ips_command_t *command;
480edc6143bSDavid Rhodus
481edc6143bSDavid Rhodus device_printf(sc->dev, "flushing cache\n");
4824751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
483edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: unable to get a command! "
484edc6143bSDavid Rhodus "can't flush cache!\n");
4854751a114SMatthew Dillon return(1);
486edc6143bSDavid Rhodus }
4874751a114SMatthew Dillon ips_send_flush_cache_cmd(command);
4884751a114SMatthew Dillon if (COMMAND_ERROR(&command->status)) {
489edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: cache flush command failed!\n");
4904751a114SMatthew Dillon return(1);
491edc6143bSDavid Rhodus }
492edc6143bSDavid Rhodus return 0;
493edc6143bSDavid Rhodus }
494edc6143bSDavid Rhodus
495edc6143bSDavid Rhodus /*
496edc6143bSDavid Rhodus * Simplified localtime to provide timevalues for ffdc.
497edc6143bSDavid Rhodus * Taken from libc/stdtime/localtime.c
498edc6143bSDavid Rhodus */
499edc6143bSDavid Rhodus static void
ips_ffdc_settime(ips_adapter_ffdc_cmd * command,time_t sctime)500edc6143bSDavid Rhodus ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
501edc6143bSDavid Rhodus {
502edc6143bSDavid Rhodus long days, rem, y;
503edc6143bSDavid Rhodus int yleap, *ip, month;
504edc6143bSDavid Rhodus int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
505edc6143bSDavid Rhodus int mon_lengths[2][IPS_MONSPERYEAR] = {
506edc6143bSDavid Rhodus { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
507edc6143bSDavid Rhodus { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
508edc6143bSDavid Rhodus };
509edc6143bSDavid Rhodus
510edc6143bSDavid Rhodus days = sctime / IPS_SECSPERDAY;
511edc6143bSDavid Rhodus rem = sctime % IPS_SECSPERDAY;
512edc6143bSDavid Rhodus
513edc6143bSDavid Rhodus command->hour = rem / IPS_SECSPERHOUR;
514edc6143bSDavid Rhodus rem = rem % IPS_SECSPERHOUR;
515edc6143bSDavid Rhodus
516edc6143bSDavid Rhodus command->minute = rem / IPS_SECSPERMIN;
517edc6143bSDavid Rhodus command->second = rem % IPS_SECSPERMIN;
518edc6143bSDavid Rhodus
519edc6143bSDavid Rhodus y = IPS_EPOCH_YEAR;
520edc6143bSDavid Rhodus while (days < 0 || days >= (long)year_lengths[yleap = ips_isleap(y)]) {
521edc6143bSDavid Rhodus long newy;
522edc6143bSDavid Rhodus
523edc6143bSDavid Rhodus newy = y + days / IPS_DAYSPERNYEAR;
524edc6143bSDavid Rhodus if (days < 0)
525edc6143bSDavid Rhodus --newy;
526edc6143bSDavid Rhodus days -= (newy - y) * IPS_DAYSPERNYEAR +
527edc6143bSDavid Rhodus IPS_LEAPS_THRU_END_OF(newy - 1) -
528edc6143bSDavid Rhodus IPS_LEAPS_THRU_END_OF(y - 1);
529edc6143bSDavid Rhodus y = newy;
530edc6143bSDavid Rhodus }
531edc6143bSDavid Rhodus command->yearH = y / 100;
532edc6143bSDavid Rhodus command->yearL = y % 100;
533edc6143bSDavid Rhodus ip = mon_lengths[yleap];
534edc6143bSDavid Rhodus for (month = 0; days >= (long)ip[month]; ++month)
535edc6143bSDavid Rhodus days = days - (long)ip[month];
536edc6143bSDavid Rhodus command->month = month + 1;
537edc6143bSDavid Rhodus command->day = days + 1;
538edc6143bSDavid Rhodus }
539edc6143bSDavid Rhodus
540edc6143bSDavid Rhodus static int
ips_send_ffdc_reset_cmd(ips_command_t * command)541edc6143bSDavid Rhodus ips_send_ffdc_reset_cmd(ips_command_t *command)
542edc6143bSDavid Rhodus {
543edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
544edc6143bSDavid Rhodus ips_adapter_ffdc_cmd *command_struct;
545edc6143bSDavid Rhodus
546edc6143bSDavid Rhodus PRINTF(10, "ips test: got a command, building ffdc reset command\n");
547edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
548edc6143bSDavid Rhodus command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
549edc6143bSDavid Rhodus command_struct->command = IPS_FFDC_CMD;
550edc6143bSDavid Rhodus command_struct->id = command->id;
551edc6143bSDavid Rhodus command_struct->reset_count = sc->ffdc_resetcount;
552edc6143bSDavid Rhodus command_struct->reset_type = 0x0;
553edc6143bSDavid Rhodus ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
554edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
555edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
556edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
5574751a114SMatthew Dillon if (command->status.value != IPS_ERROR_STATUS)
5584751a114SMatthew Dillon ips_timed_wait(command, "ffdc", 0);
559edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
560edc6143bSDavid Rhodus return 0;
561edc6143bSDavid Rhodus }
562edc6143bSDavid Rhodus
563edc6143bSDavid Rhodus int
ips_ffdc_reset(ips_softc_t * sc)564edc6143bSDavid Rhodus ips_ffdc_reset(ips_softc_t *sc)
565edc6143bSDavid Rhodus {
5664751a114SMatthew Dillon ips_command_t *command;
567edc6143bSDavid Rhodus
5684751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
569edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: unable to get a command! "
570edc6143bSDavid Rhodus "can't send ffdc reset!\n");
571a7db5ee7SJoerg Sonnenberger return 1;
572edc6143bSDavid Rhodus }
5734751a114SMatthew Dillon ips_send_ffdc_reset_cmd(command);
5744751a114SMatthew Dillon if (COMMAND_ERROR(&command->status)) {
575cce265dfSYONETANI Tomokazu /*
576cce265dfSYONETANI Tomokazu * apparently some cards may report error status for
577cce265dfSYONETANI Tomokazu * an ffdc reset command, even though it works correctly
578cce265dfSYONETANI Tomokazu * afterwards. just complain about that and proceed here.
579cce265dfSYONETANI Tomokazu */
580cce265dfSYONETANI Tomokazu device_printf(sc->dev,
581cce265dfSYONETANI Tomokazu "ERROR: ffdc reset command failed(0x%04x)!\n",
582cce265dfSYONETANI Tomokazu command->status.value);
583b56bd62aSJoerg Sonnenberger }
584edc6143bSDavid Rhodus return 0;
585edc6143bSDavid Rhodus }
586edc6143bSDavid Rhodus
587edc6143bSDavid Rhodus static void
ips_write_nvram(ips_command_t * command)588edc6143bSDavid Rhodus ips_write_nvram(ips_command_t *command)
589edc6143bSDavid Rhodus {
590edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
591edc6143bSDavid Rhodus ips_rw_nvram_cmd *command_struct;
592edc6143bSDavid Rhodus ips_nvram_page5 *nvram;
593edc6143bSDavid Rhodus
594edc6143bSDavid Rhodus /*FIXME check for error */
595edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
596edc6143bSDavid Rhodus command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
597edc6143bSDavid Rhodus command_struct->command = IPS_RW_NVRAM_CMD;
598edc6143bSDavid Rhodus command_struct->id = command->id;
599edc6143bSDavid Rhodus command_struct->pagenum = 5;
600edc6143bSDavid Rhodus command_struct->rw = 1; /* write */
601edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
602edc6143bSDavid Rhodus BUS_DMASYNC_POSTREAD);
603edc6143bSDavid Rhodus nvram = command->data_buffer;
604edc6143bSDavid Rhodus /* retrieve adapter info and save in sc */
605edc6143bSDavid Rhodus sc->adapter_type = nvram->adapter_type;
606edc6143bSDavid Rhodus strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
607edc6143bSDavid Rhodus strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
608edc6143bSDavid Rhodus nvram->operating_system = IPS_OS_FREEBSD;
609edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
610edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
611edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
612edc6143bSDavid Rhodus }
613edc6143bSDavid Rhodus
614edc6143bSDavid Rhodus static void
ips_read_nvram_callback(void * cmdptr,bus_dma_segment_t * segments,int segnum,int error)615edc6143bSDavid Rhodus ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
616edc6143bSDavid Rhodus int error)
617edc6143bSDavid Rhodus {
618edc6143bSDavid Rhodus ips_softc_t *sc;
619edc6143bSDavid Rhodus ips_command_t *command = cmdptr;
620edc6143bSDavid Rhodus ips_rw_nvram_cmd *command_struct;
621edc6143bSDavid Rhodus
622edc6143bSDavid Rhodus sc = command->sc;
623edc6143bSDavid Rhodus if (error) {
6244751a114SMatthew Dillon command->status.value = IPS_ERROR_STATUS;
625edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
626*e3869ec7SSascha Wildner kprintf("ips: error = %d in ips_read_nvram_callback\n", error);
627edc6143bSDavid Rhodus return;
628edc6143bSDavid Rhodus }
629edc6143bSDavid Rhodus command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
630edc6143bSDavid Rhodus command_struct->command = IPS_RW_NVRAM_CMD;
631edc6143bSDavid Rhodus command_struct->id = command->id;
632edc6143bSDavid Rhodus command_struct->pagenum = 5;
633edc6143bSDavid Rhodus command_struct->rw = 0;
634edc6143bSDavid Rhodus command_struct->buffaddr = segments[0].ds_addr;
635edc6143bSDavid Rhodus
636edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
637edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
638edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
639edc6143bSDavid Rhodus BUS_DMASYNC_PREREAD);
640edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
641edc6143bSDavid Rhodus }
642edc6143bSDavid Rhodus
643edc6143bSDavid Rhodus static int
ips_read_nvram(ips_command_t * command)644edc6143bSDavid Rhodus ips_read_nvram(ips_command_t *command)
645edc6143bSDavid Rhodus {
646edc6143bSDavid Rhodus int error = 0;
647edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
648edc6143bSDavid Rhodus
649edc6143bSDavid Rhodus if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
650edc6143bSDavid Rhodus /* alignemnt */ 1,
651edc6143bSDavid Rhodus /* boundary */ 0,
652edc6143bSDavid Rhodus /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
653edc6143bSDavid Rhodus /* highaddr */ BUS_SPACE_MAXADDR,
654edc6143bSDavid Rhodus /* maxsize */ IPS_NVRAM_PAGE_SIZE,
655edc6143bSDavid Rhodus /* numsegs */ 1,
656edc6143bSDavid Rhodus /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE,
657edc6143bSDavid Rhodus /* flags */ 0,
658edc6143bSDavid Rhodus &command->data_dmatag) != 0) {
659*e3869ec7SSascha Wildner kprintf("ips: can't alloc dma tag for nvram\n");
660edc6143bSDavid Rhodus error = ENOMEM;
661edc6143bSDavid Rhodus goto exit;
662edc6143bSDavid Rhodus }
663edc6143bSDavid Rhodus if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
664edc6143bSDavid Rhodus BUS_DMA_NOWAIT, &command->data_dmamap)) {
665edc6143bSDavid Rhodus error = ENOMEM;
666edc6143bSDavid Rhodus goto exit;
667edc6143bSDavid Rhodus }
668edc6143bSDavid Rhodus command->callback = ips_write_nvram;
669edc6143bSDavid Rhodus bus_dmamap_load(command->data_dmatag, command->data_dmamap,
670edc6143bSDavid Rhodus command->data_buffer, IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback,
671edc6143bSDavid Rhodus command, BUS_DMA_NOWAIT);
6724751a114SMatthew Dillon if ((command->status.value == IPS_ERROR_STATUS) ||
6734751a114SMatthew Dillon ips_timed_wait(command, "ips", 0) != 0)
674edc6143bSDavid Rhodus error = ETIMEDOUT;
675edc6143bSDavid Rhodus if (error == 0) {
676edc6143bSDavid Rhodus bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
677edc6143bSDavid Rhodus BUS_DMASYNC_POSTWRITE);
678edc6143bSDavid Rhodus }
679edc6143bSDavid Rhodus bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
680edc6143bSDavid Rhodus exit:
681edc6143bSDavid Rhodus bus_dmamem_free(command->data_dmatag, command->data_buffer,
682edc6143bSDavid Rhodus command->data_dmamap);
683edc6143bSDavid Rhodus bus_dma_tag_destroy(command->data_dmatag);
684edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
685edc6143bSDavid Rhodus return error;
686edc6143bSDavid Rhodus }
687edc6143bSDavid Rhodus
688edc6143bSDavid Rhodus int
ips_update_nvram(ips_softc_t * sc)689edc6143bSDavid Rhodus ips_update_nvram(ips_softc_t *sc)
690edc6143bSDavid Rhodus {
6914751a114SMatthew Dillon ips_command_t *command;
692edc6143bSDavid Rhodus
6934751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
694edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: unable to get a command! "
695edc6143bSDavid Rhodus "can't update nvram\n");
696edc6143bSDavid Rhodus return 1;
697edc6143bSDavid Rhodus }
6984751a114SMatthew Dillon ips_read_nvram(command);
6994751a114SMatthew Dillon if (COMMAND_ERROR(&command->status)) {
700edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: nvram update command failed!\n");
701b56bd62aSJoerg Sonnenberger return 1;
702b56bd62aSJoerg Sonnenberger }
703edc6143bSDavid Rhodus return 0;
704edc6143bSDavid Rhodus }
705edc6143bSDavid Rhodus
706edc6143bSDavid Rhodus static int
ips_send_config_sync_cmd(ips_command_t * command)707edc6143bSDavid Rhodus ips_send_config_sync_cmd(ips_command_t *command)
708edc6143bSDavid Rhodus {
709edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
710edc6143bSDavid Rhodus ips_generic_cmd *command_struct;
711edc6143bSDavid Rhodus
712edc6143bSDavid Rhodus PRINTF(10, "ips test: got a command, building flush command\n");
713edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
714edc6143bSDavid Rhodus command_struct = (ips_generic_cmd *)command->command_buffer;
715edc6143bSDavid Rhodus command_struct->command = IPS_CONFIG_SYNC_CMD;
716edc6143bSDavid Rhodus command_struct->id = command->id;
717edc6143bSDavid Rhodus command_struct->reserve2 = IPS_POCL;
718edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
719edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
720edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
7214751a114SMatthew Dillon if (command->status.value != IPS_ERROR_STATUS)
7224751a114SMatthew Dillon ips_timed_wait(command, "ipssyn", 0);
723edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
724edc6143bSDavid Rhodus return 0;
725edc6143bSDavid Rhodus }
726edc6143bSDavid Rhodus
727edc6143bSDavid Rhodus static int
ips_send_error_table_cmd(ips_command_t * command)728edc6143bSDavid Rhodus ips_send_error_table_cmd(ips_command_t *command)
729edc6143bSDavid Rhodus {
730edc6143bSDavid Rhodus ips_softc_t *sc = command->sc;
731edc6143bSDavid Rhodus ips_generic_cmd *command_struct;
732edc6143bSDavid Rhodus
733edc6143bSDavid Rhodus PRINTF(10, "ips test: got a command, building errortable command\n");
734edc6143bSDavid Rhodus command->callback = ips_wakeup_callback;
735edc6143bSDavid Rhodus command_struct = (ips_generic_cmd *)command->command_buffer;
736edc6143bSDavid Rhodus command_struct->command = IPS_ERROR_TABLE_CMD;
737edc6143bSDavid Rhodus command_struct->id = command->id;
738edc6143bSDavid Rhodus command_struct->reserve2 = IPS_CSL;
739edc6143bSDavid Rhodus bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
740edc6143bSDavid Rhodus BUS_DMASYNC_PREWRITE);
741edc6143bSDavid Rhodus sc->ips_issue_cmd(command);
7424751a114SMatthew Dillon if (command->status.value != IPS_ERROR_STATUS)
7434751a114SMatthew Dillon ips_timed_wait(command, "ipsetc", 0);
744edc6143bSDavid Rhodus ips_insert_free_cmd(sc, command);
745edc6143bSDavid Rhodus return 0;
746edc6143bSDavid Rhodus }
747edc6143bSDavid Rhodus
748edc6143bSDavid Rhodus int
ips_clear_adapter(ips_softc_t * sc)749edc6143bSDavid Rhodus ips_clear_adapter(ips_softc_t *sc)
750edc6143bSDavid Rhodus {
7514751a114SMatthew Dillon ips_command_t *command;
752edc6143bSDavid Rhodus
753edc6143bSDavid Rhodus device_printf(sc->dev, "syncing config\n");
7544751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
755edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: unable to get a command! "
756edc6143bSDavid Rhodus "can't sync cache!\n");
757edc6143bSDavid Rhodus return 1;
758edc6143bSDavid Rhodus }
7594751a114SMatthew Dillon ips_send_config_sync_cmd(command);
7604751a114SMatthew Dillon if (COMMAND_ERROR(&command->status)) {
761edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: cache sync command failed!\n");
762edc6143bSDavid Rhodus return 1;
763edc6143bSDavid Rhodus }
764edc6143bSDavid Rhodus device_printf(sc->dev, "clearing error table\n");
7654751a114SMatthew Dillon if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
766edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: unable to get a command! "
767edc6143bSDavid Rhodus "can't sync cache!\n");
768edc6143bSDavid Rhodus return 1;
769edc6143bSDavid Rhodus }
7704751a114SMatthew Dillon ips_send_error_table_cmd(command);
7714751a114SMatthew Dillon if (COMMAND_ERROR(&command->status)) {
772edc6143bSDavid Rhodus device_printf(sc->dev, "ERROR: etable command failed!\n");
773edc6143bSDavid Rhodus return 1;
774edc6143bSDavid Rhodus }
775edc6143bSDavid Rhodus return 0;
776edc6143bSDavid Rhodus }
777