dma: defer delivery if STARTTLS fails
[dragonfly.git] / sys / dev / raid / ips / ips_commands.c
blob9a1f9cd5ca0eee05747561dba3d96d8e4442bd14
1 /*-
2 * Written by: David Jeffery
3 * Copyright (c) 2002 Adaptec Inc.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
27 * $FreeBSD: src/sys/dev/ips/ips_commands.c,v 1.10 2004/05/30 04:01:29 scottl Exp $
28 * $DragonFly: src/sys/dev/raid/ips/ips_commands.c,v 1.13 2006/12/22 23:26:23 swildner Exp $
31 #include <sys/devicestat.h>
32 #include <dev/raid/ips/ips.h>
33 #include <dev/raid/ips/ips_disk.h>
35 int
36 ips_timed_wait(ips_command_t *command, const char *id, int timo)
38 int error = 0;
40 while (command->completed == 0) {
41 crit_enter();
42 if (command->completed == 0)
43 error = tsleep(&command->completed, 0, id, timo);
44 crit_exit();
45 if (error == EWOULDBLOCK) {
46 error = ETIMEDOUT;
47 break;
50 return(error);
54 * This is an interrupt callback. It is called from
55 * interrupt context when the adapter has completed the
56 * command, and wakes up anyone waiting on the command.
58 static void
59 ips_wakeup_callback(ips_command_t *command)
61 bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
62 BUS_DMASYNC_POSTWRITE);
63 command->completed = 1;
64 wakeup(&command->completed);
68 * Below are a series of functions for sending an IO request
69 * to the adapter. The flow order is: start, send, callback, finish.
70 * The caller must have already assembled an iorequest struct to hold
71 * the details of the IO request.
73 static void
74 ips_io_request_finish(ips_command_t *command)
76 struct bio *bio = command->arg;
78 if (ips_read_request(bio)) {
79 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
80 BUS_DMASYNC_POSTREAD);
81 } else {
82 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
83 BUS_DMASYNC_POSTWRITE);
85 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
86 if (COMMAND_ERROR(&command->status)) {
87 bio->bio_buf->b_flags |=B_ERROR;
88 bio->bio_buf->b_error = EIO;
90 ips_insert_free_cmd(command->sc, command);
91 ipsd_finish(bio);
94 static void
95 ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
96 int error)
98 ips_softc_t *sc;
99 ips_command_t *command = cmdptr;
100 ips_sg_element_t *sg_list;
101 ips_io_cmd *command_struct;
102 struct bio *bio = command->arg;
103 struct buf *bp = bio->bio_buf;
104 ipsdisk_softc_t *dsc;
105 int i, length = 0;
106 u_int8_t cmdtype;
108 sc = command->sc;
109 if (error) {
110 kprintf("ips: error = %d in ips_sg_request_callback\n", error);
111 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
112 bp->b_flags |= B_ERROR;
113 bp->b_error = ENOMEM;
114 ips_insert_free_cmd(sc, command);
115 ipsd_finish(bio);
116 return;
118 dsc = bio->bio_driver_info;
119 command_struct = (ips_io_cmd *)command->command_buffer;
120 command_struct->id = command->id;
121 command_struct->drivenum = dsc->sc->drives[dsc->disk_number].drivenum;
123 if (segnum != 1) {
124 if (ips_read_request(bio))
125 cmdtype = IPS_SG_READ_CMD;
126 else
127 cmdtype = IPS_SG_WRITE_CMD;
128 command_struct->segnum = segnum;
129 sg_list = (ips_sg_element_t *)((u_int8_t *)
130 command->command_buffer + IPS_COMMAND_LEN);
131 for (i = 0; i < segnum; i++) {
132 sg_list[i].addr = segments[i].ds_addr;
133 sg_list[i].len = segments[i].ds_len;
134 length += segments[i].ds_len;
136 command_struct->buffaddr =
137 (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
138 } else {
139 if (ips_read_request(bio))
140 cmdtype = IPS_READ_CMD;
141 else
142 cmdtype = IPS_WRITE_CMD;
143 command_struct->buffaddr = segments[0].ds_addr;
144 length = segments[0].ds_len;
146 command_struct->command = cmdtype;
147 command_struct->lba = bio->bio_offset / IPS_BLKSIZE;
148 length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
149 command_struct->length = length;
150 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
151 BUS_DMASYNC_PREWRITE);
152 if (ips_read_request(bio)) {
153 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
154 BUS_DMASYNC_PREREAD);
155 } else {
156 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
157 BUS_DMASYNC_PREWRITE);
160 * the cast to long long below is necessary because our b_pblkno
161 * is 32bit wide whereas it's 64bit on FreeBSD-CURRENT.
163 PRINTF(10, "ips test: command id: %d segments: %d "
164 "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
165 bio->bio_offset / IPS_BLKSIZE,
166 length, segments[0].ds_len);
168 sc->ips_issue_cmd(command);
169 return;
172 static int
173 ips_send_io_request(ips_command_t *command, struct bio *bio)
175 struct buf *bp = bio->bio_buf;
177 command->callback = ips_io_request_finish;
178 command->arg = bio;
179 PRINTF(10, "ips test: : bcount %ld\n", bp->b_bcount);
180 bus_dmamap_load(command->data_dmatag, command->data_dmamap,
181 bp->b_data, bp->b_bcount,
182 ips_io_request_callback, command, 0);
183 return 0;
186 void
187 ips_start_io_request(ips_softc_t *sc)
189 ips_command_t *command;
190 struct bio *bio;
192 bio = bioq_first(&sc->bio_queue);
193 if (bio == NULL)
194 return;
195 if (ips_get_free_cmd(sc, &command, 0) != 0)
196 return;
197 bioq_remove(&sc->bio_queue, bio);
198 ips_send_io_request(command, bio);
202 * Below are a series of functions for sending an adapter info request
203 * to the adapter. The flow order is: get, send, callback. It uses
204 * the generic finish callback at the top of this file.
205 * This can be used to get configuration/status info from the card
207 static void
208 ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum,
209 int error)
211 ips_softc_t *sc;
212 ips_command_t *command = cmdptr;
213 ips_adapter_info_cmd *command_struct;
214 sc = command->sc;
215 if (error) {
216 command->status.value = IPS_ERROR_STATUS; /* a lovely error value */
217 ips_insert_free_cmd(sc, command);
218 kprintf("ips: error = %d in ips_get_adapter_info\n", error);
219 return;
221 command_struct = (ips_adapter_info_cmd *)command->command_buffer;
222 command_struct->command = IPS_ADAPTER_INFO_CMD;
223 command_struct->id = command->id;
224 command_struct->buffaddr = segments[0].ds_addr;
226 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
227 BUS_DMASYNC_PREWRITE);
228 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
229 BUS_DMASYNC_PREREAD);
230 sc->ips_issue_cmd(command);
233 static int
234 ips_send_adapter_info_cmd(ips_command_t *command)
236 ips_softc_t *sc = command->sc;
237 int error = 0;
239 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
240 /* alignemnt */ 1,
241 /* boundary */ 0,
242 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
243 /* highaddr */ BUS_SPACE_MAXADDR,
244 /* filter */ NULL,
245 /* filterarg */ NULL,
246 /* maxsize */ IPS_ADAPTER_INFO_LEN,
247 /* numsegs */ 1,
248 /* maxsegsize*/ IPS_ADAPTER_INFO_LEN,
249 /* flags */ 0,
250 &command->data_dmatag) != 0) {
251 kprintf("ips: can't alloc dma tag for adapter status\n");
252 error = ENOMEM;
253 goto exit;
255 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
256 BUS_DMA_NOWAIT, &command->data_dmamap)) {
257 error = ENOMEM;
258 goto exit;
260 command->callback = ips_wakeup_callback;
261 bus_dmamap_load(command->data_dmatag, command->data_dmamap,
262 command->data_buffer, IPS_ADAPTER_INFO_LEN,
263 ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
264 if ((command->status.value == IPS_ERROR_STATUS) ||
265 ips_timed_wait(command, "ips", 30 * hz) != 0)
266 error = ETIMEDOUT;
267 if (error == 0) {
268 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
269 BUS_DMASYNC_POSTREAD);
270 memcpy(&(sc->adapter_info), command->data_buffer,
271 IPS_ADAPTER_INFO_LEN);
273 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
274 exit:
275 /* I suppose I should clean up my memory allocations */
276 bus_dmamem_free(command->data_dmatag, command->data_buffer,
277 command->data_dmamap);
278 bus_dma_tag_destroy(command->data_dmatag);
279 ips_insert_free_cmd(sc, command);
280 return error;
284 ips_get_adapter_info(ips_softc_t *sc)
286 ips_command_t *command;
287 int error = 0;
289 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
290 device_printf(sc->dev, "unable to get adapter configuration\n");
291 return ENXIO;
293 ips_send_adapter_info_cmd(command);
294 if (COMMAND_ERROR(&command->status))
295 error = ENXIO;
296 return error;
300 * Below are a series of functions for sending a drive info request
301 * to the adapter. The flow order is: get, send, callback. It uses
302 * the generic finish callback at the top of this file.
303 * This can be used to get drive status info from the card
305 static void
306 ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
307 int error)
309 ips_softc_t *sc;
310 ips_command_t *command = cmdptr;
311 ips_drive_cmd *command_struct;
313 sc = command->sc;
314 if (error) {
316 command->status.value = IPS_ERROR_STATUS;
317 ips_insert_free_cmd(sc, command);
318 kprintf("ips: error = %d in ips_get_drive_info\n", error);
319 return;
321 command_struct = (ips_drive_cmd *)command->command_buffer;
322 command_struct->command = IPS_DRIVE_INFO_CMD;
323 command_struct->id = command->id;
324 command_struct->buffaddr = segments[0].ds_addr;
325 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
326 BUS_DMASYNC_PREWRITE);
327 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
328 BUS_DMASYNC_PREREAD);
329 sc->ips_issue_cmd(command);
332 static int
333 ips_send_drive_info_cmd(ips_command_t *command)
335 int error = 0;
336 ips_softc_t *sc = command->sc;
337 ips_drive_info_t *driveinfo;
339 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
340 /* alignemnt */ 1,
341 /* boundary */ 0,
342 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
343 /* highaddr */ BUS_SPACE_MAXADDR,
344 /* filter */ NULL,
345 /* filterarg */ NULL,
346 /* maxsize */ IPS_DRIVE_INFO_LEN,
347 /* numsegs */ 1,
348 /* maxsegsize*/ IPS_DRIVE_INFO_LEN,
349 /* flags */ 0,
350 &command->data_dmatag) != 0) {
351 kprintf("ips: can't alloc dma tag for drive status\n");
352 error = ENOMEM;
353 goto exit;
355 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
356 BUS_DMA_NOWAIT, &command->data_dmamap)) {
357 error = ENOMEM;
358 goto exit;
360 command->callback = ips_wakeup_callback;
361 bus_dmamap_load(command->data_dmatag, command->data_dmamap,
362 command->data_buffer,IPS_DRIVE_INFO_LEN,
363 ips_drive_info_callback, command, BUS_DMA_NOWAIT);
364 if ((command->status.value == IPS_ERROR_STATUS) ||
365 ips_timed_wait(command, "ips", 10 * hz) != 0)
366 error = ETIMEDOUT;
368 if (error == 0) {
369 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
370 BUS_DMASYNC_POSTREAD);
371 driveinfo = command->data_buffer;
372 memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
373 sc->drivecount = driveinfo->drivecount;
374 device_printf(sc->dev, "logical drives: %d\n", sc->drivecount);
376 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
377 exit:
378 /* I suppose I should clean up my memory allocations */
379 bus_dmamem_free(command->data_dmatag, command->data_buffer,
380 command->data_dmamap);
381 bus_dma_tag_destroy(command->data_dmatag);
382 ips_insert_free_cmd(sc, command);
383 return error;
387 ips_get_drive_info(ips_softc_t *sc)
389 int error = 0;
390 ips_command_t *command;
392 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
393 device_printf(sc->dev, "unable to get drive configuration\n");
394 return ENXIO;
396 ips_send_drive_info_cmd(command);
397 if (COMMAND_ERROR(&command->status))
398 error = ENXIO;
399 return error;
403 * Below is a pair of functions for making sure data is safely
404 * on disk by flushing the adapter's cache.
406 static int
407 ips_send_flush_cache_cmd(ips_command_t *command)
409 ips_softc_t *sc = command->sc;
410 ips_generic_cmd *command_struct;
412 PRINTF(10,"ips test: got a command, building flush command\n");
413 command->callback = ips_wakeup_callback;
414 command_struct = (ips_generic_cmd *)command->command_buffer;
415 command_struct->command = IPS_CACHE_FLUSH_CMD;
416 command_struct->id = command->id;
417 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
418 BUS_DMASYNC_PREWRITE);
419 sc->ips_issue_cmd(command);
420 if (command->status.value != IPS_ERROR_STATUS)
421 ips_timed_wait(command, "flush2", 0);
422 ips_insert_free_cmd(sc, command);
423 return 0;
427 ips_flush_cache(ips_softc_t *sc)
429 ips_command_t *command;
431 device_printf(sc->dev, "flushing cache\n");
432 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
433 device_printf(sc->dev, "ERROR: unable to get a command! "
434 "can't flush cache!\n");
435 return(1);
437 ips_send_flush_cache_cmd(command);
438 if (COMMAND_ERROR(&command->status)) {
439 device_printf(sc->dev, "ERROR: cache flush command failed!\n");
440 return(1);
442 return 0;
446 * Simplified localtime to provide timevalues for ffdc.
447 * Taken from libc/stdtime/localtime.c
449 static void
450 ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
452 long days, rem, y;
453 int yleap, *ip, month;
454 int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
455 int mon_lengths[2][IPS_MONSPERYEAR] = {
456 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
457 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
460 days = sctime / IPS_SECSPERDAY;
461 rem = sctime % IPS_SECSPERDAY;
463 command->hour = rem / IPS_SECSPERHOUR;
464 rem = rem % IPS_SECSPERHOUR;
466 command->minute = rem / IPS_SECSPERMIN;
467 command->second = rem % IPS_SECSPERMIN;
469 y = IPS_EPOCH_YEAR;
470 while (days < 0 || days >= (long)year_lengths[yleap = ips_isleap(y)]) {
471 long newy;
473 newy = y + days / IPS_DAYSPERNYEAR;
474 if (days < 0)
475 --newy;
476 days -= (newy - y) * IPS_DAYSPERNYEAR +
477 IPS_LEAPS_THRU_END_OF(newy - 1) -
478 IPS_LEAPS_THRU_END_OF(y - 1);
479 y = newy;
481 command->yearH = y / 100;
482 command->yearL = y % 100;
483 ip = mon_lengths[yleap];
484 for (month = 0; days >= (long)ip[month]; ++month)
485 days = days - (long)ip[month];
486 command->month = month + 1;
487 command->day = days + 1;
490 static int
491 ips_send_ffdc_reset_cmd(ips_command_t *command)
493 ips_softc_t *sc = command->sc;
494 ips_adapter_ffdc_cmd *command_struct;
496 PRINTF(10, "ips test: got a command, building ffdc reset command\n");
497 command->callback = ips_wakeup_callback;
498 command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
499 command_struct->command = IPS_FFDC_CMD;
500 command_struct->id = command->id;
501 command_struct->reset_count = sc->ffdc_resetcount;
502 command_struct->reset_type = 0x0;
503 ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
504 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
505 BUS_DMASYNC_PREWRITE);
506 sc->ips_issue_cmd(command);
507 if (command->status.value != IPS_ERROR_STATUS)
508 ips_timed_wait(command, "ffdc", 0);
509 ips_insert_free_cmd(sc, command);
510 return 0;
514 ips_ffdc_reset(ips_softc_t *sc)
516 ips_command_t *command;
518 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
519 device_printf(sc->dev, "ERROR: unable to get a command! "
520 "can't send ffdc reset!\n");
521 return 1;
523 ips_send_ffdc_reset_cmd(command);
524 if (COMMAND_ERROR(&command->status)) {
526 * apparently some cards may report error status for
527 * an ffdc reset command, even though it works correctly
528 * afterwards. just complain about that and proceed here.
530 device_printf(sc->dev,
531 "ERROR: ffdc reset command failed(0x%04x)!\n",
532 command->status.value);
534 return 0;
537 static void
538 ips_write_nvram(ips_command_t *command)
540 ips_softc_t *sc = command->sc;
541 ips_rw_nvram_cmd *command_struct;
542 ips_nvram_page5 *nvram;
544 /*FIXME check for error */
545 command->callback = ips_wakeup_callback;
546 command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
547 command_struct->command = IPS_RW_NVRAM_CMD;
548 command_struct->id = command->id;
549 command_struct->pagenum = 5;
550 command_struct->rw = 1; /* write */
551 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
552 BUS_DMASYNC_POSTREAD);
553 nvram = command->data_buffer;
554 /* retrieve adapter info and save in sc */
555 sc->adapter_type = nvram->adapter_type;
556 strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
557 strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
558 nvram->operating_system = IPS_OS_FREEBSD;
559 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
560 BUS_DMASYNC_PREWRITE);
561 sc->ips_issue_cmd(command);
564 static void
565 ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
566 int error)
568 ips_softc_t *sc;
569 ips_command_t *command = cmdptr;
570 ips_rw_nvram_cmd *command_struct;
572 sc = command->sc;
573 if (error) {
574 command->status.value = IPS_ERROR_STATUS;
575 ips_insert_free_cmd(sc, command);
576 kprintf("ips: error = %d in ips_read_nvram_callback\n", error);
577 return;
579 command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
580 command_struct->command = IPS_RW_NVRAM_CMD;
581 command_struct->id = command->id;
582 command_struct->pagenum = 5;
583 command_struct->rw = 0;
584 command_struct->buffaddr = segments[0].ds_addr;
586 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
587 BUS_DMASYNC_PREWRITE);
588 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
589 BUS_DMASYNC_PREREAD);
590 sc->ips_issue_cmd(command);
593 static int
594 ips_read_nvram(ips_command_t *command)
596 int error = 0;
597 ips_softc_t *sc = command->sc;
599 if (bus_dma_tag_create( /* parent */ sc->adapter_dmatag,
600 /* alignemnt */ 1,
601 /* boundary */ 0,
602 /* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
603 /* highaddr */ BUS_SPACE_MAXADDR,
604 /* filter */ NULL,
605 /* filterarg */ NULL,
606 /* maxsize */ IPS_NVRAM_PAGE_SIZE,
607 /* numsegs */ 1,
608 /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE,
609 /* flags */ 0,
610 &command->data_dmatag) != 0) {
611 kprintf("ips: can't alloc dma tag for nvram\n");
612 error = ENOMEM;
613 goto exit;
615 if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
616 BUS_DMA_NOWAIT, &command->data_dmamap)) {
617 error = ENOMEM;
618 goto exit;
620 command->callback = ips_write_nvram;
621 bus_dmamap_load(command->data_dmatag, command->data_dmamap,
622 command->data_buffer, IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback,
623 command, BUS_DMA_NOWAIT);
624 if ((command->status.value == IPS_ERROR_STATUS) ||
625 ips_timed_wait(command, "ips", 0) != 0)
626 error = ETIMEDOUT;
627 if (error == 0) {
628 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
629 BUS_DMASYNC_POSTWRITE);
631 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
632 exit:
633 bus_dmamem_free(command->data_dmatag, command->data_buffer,
634 command->data_dmamap);
635 bus_dma_tag_destroy(command->data_dmatag);
636 ips_insert_free_cmd(sc, command);
637 return error;
641 ips_update_nvram(ips_softc_t *sc)
643 ips_command_t *command;
645 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
646 device_printf(sc->dev, "ERROR: unable to get a command! "
647 "can't update nvram\n");
648 return 1;
650 ips_read_nvram(command);
651 if (COMMAND_ERROR(&command->status)) {
652 device_printf(sc->dev, "ERROR: nvram update command failed!\n");
653 return 1;
655 return 0;
658 static int
659 ips_send_config_sync_cmd(ips_command_t *command)
661 ips_softc_t *sc = command->sc;
662 ips_generic_cmd *command_struct;
664 PRINTF(10, "ips test: got a command, building flush command\n");
665 command->callback = ips_wakeup_callback;
666 command_struct = (ips_generic_cmd *)command->command_buffer;
667 command_struct->command = IPS_CONFIG_SYNC_CMD;
668 command_struct->id = command->id;
669 command_struct->reserve2 = IPS_POCL;
670 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
671 BUS_DMASYNC_PREWRITE);
672 sc->ips_issue_cmd(command);
673 if (command->status.value != IPS_ERROR_STATUS)
674 ips_timed_wait(command, "ipssyn", 0);
675 ips_insert_free_cmd(sc, command);
676 return 0;
679 static int
680 ips_send_error_table_cmd(ips_command_t *command)
682 ips_softc_t *sc = command->sc;
683 ips_generic_cmd *command_struct;
685 PRINTF(10, "ips test: got a command, building errortable command\n");
686 command->callback = ips_wakeup_callback;
687 command_struct = (ips_generic_cmd *)command->command_buffer;
688 command_struct->command = IPS_ERROR_TABLE_CMD;
689 command_struct->id = command->id;
690 command_struct->reserve2 = IPS_CSL;
691 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
692 BUS_DMASYNC_PREWRITE);
693 sc->ips_issue_cmd(command);
694 if (command->status.value != IPS_ERROR_STATUS)
695 ips_timed_wait(command, "ipsetc", 0);
696 ips_insert_free_cmd(sc, command);
697 return 0;
701 ips_clear_adapter(ips_softc_t *sc)
703 ips_command_t *command;
705 device_printf(sc->dev, "syncing config\n");
706 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
707 device_printf(sc->dev, "ERROR: unable to get a command! "
708 "can't sync cache!\n");
709 return 1;
711 ips_send_config_sync_cmd(command);
712 if (COMMAND_ERROR(&command->status)) {
713 device_printf(sc->dev, "ERROR: cache sync command failed!\n");
714 return 1;
716 device_printf(sc->dev, "clearing error table\n");
717 if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
718 device_printf(sc->dev, "ERROR: unable to get a command! "
719 "can't sync cache!\n");
720 return 1;
722 ips_send_error_table_cmd(command);
723 if (COMMAND_ERROR(&command->status)) {
724 device_printf(sc->dev, "ERROR: etable command failed!\n");
725 return 1;
727 return 0;