Some of ServeRAID card may report an unusual status code after
[dragonfly.git] / sys / dev / raid / ips / ips_commands.c
1 /*-
2  * Written by: David Jeffery
3  * Copyright (c) 2002 Adaptec Inc.
4  * All rights reserved.
5  *
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.
14  *
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.
26  *
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.10 2006/01/01 16:53:15 y0netan1 Exp $
29  */
30
31 #include <dev/raid/ips/ips.h>
32
33 int
34 ips_timed_wait(ips_command_t *command, const char *id, int timo)
35 {
36         int error = 0;
37
38         while (command->completed == 0) {
39                 crit_enter();
40                 if (command->completed == 0)
41                         error = tsleep(&command->completed, 0, id, timo);
42                 crit_exit();
43                 if (error == EWOULDBLOCK) {
44                         error = ETIMEDOUT;
45                         break;
46                 }
47         }
48         return(error);
49 }
50
51 /*
52  * This is an interrupt callback.  It is called from
53  * interrupt context when the adapter has completed the
54  * command, and wakes up anyone waiting on the command.
55  */
56 static void
57 ips_wakeup_callback(ips_command_t *command)
58 {
59         bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
60                         BUS_DMASYNC_POSTWRITE);
61         command->completed = 1;
62         wakeup(&command->completed);
63 }
64
65 /*
66  * Below are a series of functions for sending an IO request
67  * to the adapter.  The flow order is: start, send, callback, finish.
68  * The caller must have already assembled an iorequest struct to hold
69  * the details of the IO request.
70  */
71 static void
72 ips_io_request_finish(ips_command_t *command)
73 {
74         struct bio *iobuf = command->arg;
75
76         if (ips_read_request(iobuf)) {
77                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
78                                 BUS_DMASYNC_POSTREAD);
79         } else {
80                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
81                                 BUS_DMASYNC_POSTWRITE);
82         }
83         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
84         if (COMMAND_ERROR(&command->status)) {
85                 iobuf->bio_flags |=BIO_ERROR;
86                 iobuf->bio_error = EIO;
87         }
88         ips_insert_free_cmd(command->sc, command);
89         ipsd_finish(iobuf);
90 }
91
92 static void
93 ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
94                         int error)
95 {
96         ips_softc_t *sc;
97         ips_command_t *command = cmdptr;
98         ips_sg_element_t *sg_list;
99         ips_io_cmd *command_struct;
100         struct bio *iobuf = command->arg;
101         int i, length = 0;
102         u_int8_t cmdtype;
103
104         sc = command->sc;
105         if (error) {
106                 printf("ips: error = %d in ips_sg_request_callback\n", error);
107                 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
108                 iobuf->bio_flags |= BIO_ERROR;
109                 iobuf->bio_error = ENOMEM;
110                 ips_insert_free_cmd(sc, command);
111                 ipsd_finish(iobuf);
112                 return;
113         }
114         command_struct = (ips_io_cmd *)command->command_buffer;
115         command_struct->id = command->id;
116         command_struct->drivenum = (uintptr_t)iobuf->bio_driver1;
117         if (segnum != 1) {
118                 if (ips_read_request(iobuf))
119                         cmdtype = IPS_SG_READ_CMD;
120                 else
121                         cmdtype = IPS_SG_WRITE_CMD;
122                 command_struct->segnum = segnum;
123                 sg_list = (ips_sg_element_t *)((u_int8_t *)
124                            command->command_buffer + IPS_COMMAND_LEN);
125                 for (i = 0; i < segnum; i++) {
126                         sg_list[i].addr = segments[i].ds_addr;
127                         sg_list[i].len = segments[i].ds_len;
128                         length += segments[i].ds_len;
129                 }
130                 command_struct->buffaddr =
131                     (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
132         } else {
133                 if (ips_read_request(iobuf))
134                         cmdtype = IPS_READ_CMD;
135                 else
136                         cmdtype = IPS_WRITE_CMD;
137                 command_struct->buffaddr = segments[0].ds_addr;
138                 length = segments[0].ds_len;
139         }
140         command_struct->command = cmdtype;
141         command_struct->lba = iobuf->bio_pblkno;
142         length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
143         command_struct->length = length;
144         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
145                         BUS_DMASYNC_PREWRITE);
146         if (ips_read_request(iobuf)) {
147                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
148                                 BUS_DMASYNC_PREREAD);
149         } else {
150                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
151                                 BUS_DMASYNC_PREWRITE);
152         }
153         /*
154          * the cast to long long below is necessary because our b_pblkno
155          * is 32bit wide whereas it's 64bit on FreeBSD-CURRENT.
156          */
157         PRINTF(10, "ips test: command id: %d segments: %d "
158                 "pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
159                 (long long)iobuf->bio_pblkno,
160                 length, segments[0].ds_len);
161
162         sc->ips_issue_cmd(command);
163         return;
164 }
165
166 static int
167 ips_send_io_request(ips_command_t *command, struct buf *iobuf)
168 {
169         command->callback = ips_io_request_finish;
170         command->arg = iobuf;
171         PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount);
172         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
173                         iobuf->bio_data, iobuf->bio_bcount,
174                         ips_io_request_callback, command, 0);
175         return 0;
176 }
177
178 void
179 ips_start_io_request(ips_softc_t *sc)
180 {
181         ips_command_t *command;
182         struct bio *iobuf;
183
184         iobuf = bufq_first(&sc->queue);
185         if (iobuf == NULL)
186                 return;
187         if (ips_get_free_cmd(sc, &command, 0) != 0)
188                 return;
189         bufq_remove(&sc->queue, iobuf);
190         ips_send_io_request(command, iobuf);
191 }
192
193 /*
194  * Below are a series of functions for sending an adapter info request
195  * to the adapter.  The flow order is: get, send, callback. It uses
196  * the generic finish callback at the top of this file.
197  * This can be used to get configuration/status info from the card
198  */
199 static void
200 ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum,
201                           int error)
202 {
203         ips_softc_t *sc;
204         ips_command_t *command = cmdptr;
205         ips_adapter_info_cmd *command_struct;
206         sc = command->sc;
207         if (error) {
208                 command->status.value = IPS_ERROR_STATUS; /* a lovely error value */
209                 ips_insert_free_cmd(sc, command);
210                 printf("ips: error = %d in ips_get_adapter_info\n", error);
211                 return;
212         }
213         command_struct = (ips_adapter_info_cmd *)command->command_buffer;
214         command_struct->command = IPS_ADAPTER_INFO_CMD;
215         command_struct->id = command->id;
216         command_struct->buffaddr = segments[0].ds_addr;
217
218         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
219                         BUS_DMASYNC_PREWRITE);
220         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
221                         BUS_DMASYNC_PREREAD);
222         sc->ips_issue_cmd(command);
223 }
224
225 static int
226 ips_send_adapter_info_cmd(ips_command_t *command)
227 {
228         ips_softc_t *sc = command->sc;
229         int error = 0;
230
231         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
232                                 /* alignemnt */ 1,
233                                 /* boundary  */ 0,
234                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
235                                 /* highaddr  */ BUS_SPACE_MAXADDR,
236                                 /* filter    */ NULL,
237                                 /* filterarg */ NULL,
238                                 /* maxsize   */ IPS_ADAPTER_INFO_LEN,
239                                 /* numsegs   */ 1,
240                                 /* maxsegsize*/ IPS_ADAPTER_INFO_LEN,
241                                 /* flags     */ 0,
242                                 &command->data_dmatag) != 0) {
243                 printf("ips: can't alloc dma tag for adapter status\n");
244                 error = ENOMEM;
245                 goto exit;
246         }
247         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
248            BUS_DMA_NOWAIT, &command->data_dmamap)) {
249                 error = ENOMEM;
250                 goto exit;
251         }
252         command->callback = ips_wakeup_callback;
253         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
254             command->data_buffer, IPS_ADAPTER_INFO_LEN,
255             ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
256         if ((command->status.value == IPS_ERROR_STATUS) ||
257             ips_timed_wait(command, "ips", 30 * hz) != 0)
258                 error = ETIMEDOUT;
259         if (error == 0) {
260                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
261                     BUS_DMASYNC_POSTREAD);
262                 memcpy(&(sc->adapter_info), command->data_buffer,
263                         IPS_ADAPTER_INFO_LEN);
264         }
265         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
266 exit:
267         /* I suppose I should clean up my memory allocations */
268         bus_dmamem_free(command->data_dmatag, command->data_buffer,
269             command->data_dmamap);
270         bus_dma_tag_destroy(command->data_dmatag);
271         ips_insert_free_cmd(sc, command);
272         return error;
273 }
274
275 int
276 ips_get_adapter_info(ips_softc_t *sc)
277 {
278         ips_command_t *command;
279         int error = 0;
280
281         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
282                 device_printf(sc->dev, "unable to get adapter configuration\n");
283                 return ENXIO;
284         }
285         ips_send_adapter_info_cmd(command);
286         if (COMMAND_ERROR(&command->status))
287                 error = ENXIO;
288         return error;
289 }
290
291 /*
292  * Below are a series of functions for sending a drive info request
293  * to the adapter.  The flow order is: get, send, callback. It uses
294  * the generic finish callback at the top of this file.
295  * This can be used to get drive status info from the card
296  */
297 static void
298 ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
299                         int error)
300 {
301         ips_softc_t *sc;
302         ips_command_t *command = cmdptr;
303         ips_drive_cmd *command_struct;
304
305         sc = command->sc;
306         if (error) {
307
308                 command->status.value = IPS_ERROR_STATUS;
309                 ips_insert_free_cmd(sc, command);
310                 printf("ips: error = %d in ips_get_drive_info\n", error);
311                 return;
312         }
313         command_struct = (ips_drive_cmd *)command->command_buffer;
314         command_struct->command = IPS_DRIVE_INFO_CMD;
315         command_struct->id = command->id;
316         command_struct->buffaddr = segments[0].ds_addr;
317         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
318             BUS_DMASYNC_PREWRITE);
319         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
320             BUS_DMASYNC_PREREAD);
321         sc->ips_issue_cmd(command);
322 }
323
324 static int
325 ips_send_drive_info_cmd(ips_command_t *command)
326 {
327         int error = 0;
328         ips_softc_t *sc = command->sc;
329         ips_drive_info_t *driveinfo;
330
331         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
332                                 /* alignemnt */ 1,
333                                 /* boundary  */ 0,
334                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
335                                 /* highaddr  */ BUS_SPACE_MAXADDR,
336                                 /* filter    */ NULL,
337                                 /* filterarg */ NULL,
338                                 /* maxsize   */ IPS_DRIVE_INFO_LEN,
339                                 /* numsegs   */ 1,
340                                 /* maxsegsize*/ IPS_DRIVE_INFO_LEN,
341                                 /* flags     */ 0,
342                                 &command->data_dmatag) != 0) {
343                 printf("ips: can't alloc dma tag for drive status\n");
344                 error = ENOMEM;
345                 goto exit;
346         }
347         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
348             BUS_DMA_NOWAIT, &command->data_dmamap)) {
349                 error = ENOMEM;
350                 goto exit;
351         }
352         command->callback = ips_wakeup_callback;
353         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
354             command->data_buffer,IPS_DRIVE_INFO_LEN,
355             ips_drive_info_callback, command, BUS_DMA_NOWAIT);
356         if ((command->status.value == IPS_ERROR_STATUS) ||
357             ips_timed_wait(command, "ips", 10 * hz) != 0)
358                 error = ETIMEDOUT;
359
360         if (error == 0) {
361                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
362                     BUS_DMASYNC_POSTREAD);
363                 driveinfo = command->data_buffer;
364                 memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
365                 sc->drivecount = driveinfo->drivecount;
366                 device_printf(sc->dev, "logical drives: %d\n", sc->drivecount);
367         }
368         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
369 exit:
370         /* I suppose I should clean up my memory allocations */
371         bus_dmamem_free(command->data_dmatag, command->data_buffer,
372                         command->data_dmamap);
373         bus_dma_tag_destroy(command->data_dmatag);
374         ips_insert_free_cmd(sc, command);
375         return error;
376 }
377
378 int
379 ips_get_drive_info(ips_softc_t *sc)
380 {
381         int error = 0;
382         ips_command_t *command;
383
384         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
385                 device_printf(sc->dev, "unable to get drive configuration\n");
386                 return ENXIO;
387         }
388         ips_send_drive_info_cmd(command);
389         if (COMMAND_ERROR(&command->status))
390                 error = ENXIO;
391         return error;
392 }
393
394 /*
395  * Below is a pair of functions for making sure data is safely
396  * on disk by flushing the adapter's cache.
397  */
398 static int
399 ips_send_flush_cache_cmd(ips_command_t *command)
400 {
401         ips_softc_t *sc = command->sc;
402         ips_generic_cmd *command_struct;
403
404         PRINTF(10,"ips test: got a command, building flush command\n");
405         command->callback = ips_wakeup_callback;
406         command_struct = (ips_generic_cmd *)command->command_buffer;
407         command_struct->command = IPS_CACHE_FLUSH_CMD;
408         command_struct->id = command->id;
409         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
410             BUS_DMASYNC_PREWRITE);
411         sc->ips_issue_cmd(command);
412         if (command->status.value != IPS_ERROR_STATUS)
413                 ips_timed_wait(command, "flush2", 0);
414         ips_insert_free_cmd(sc, command);
415         return 0;
416 }
417
418 int
419 ips_flush_cache(ips_softc_t *sc)
420 {
421         ips_command_t *command;
422
423         device_printf(sc->dev, "flushing cache\n");
424         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
425                 device_printf(sc->dev, "ERROR: unable to get a command! "
426                     "can't flush cache!\n");
427                 return(1);
428         }
429         ips_send_flush_cache_cmd(command);
430         if (COMMAND_ERROR(&command->status)) {
431                 device_printf(sc->dev, "ERROR: cache flush command failed!\n");
432                 return(1);
433         }
434         return 0;
435 }
436
437 /*
438  * Simplified localtime to provide timevalues for ffdc.
439  * Taken from libc/stdtime/localtime.c
440  */
441 static void
442 ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
443 {
444         long    days, rem, y;
445         int     yleap, *ip, month;
446         int     year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
447         int     mon_lengths[2][IPS_MONSPERYEAR] = {
448                 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
449                 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
450         };
451
452         days = sctime / IPS_SECSPERDAY;
453         rem  = sctime % IPS_SECSPERDAY;
454
455         command->hour = rem / IPS_SECSPERHOUR;
456         rem           = rem % IPS_SECSPERHOUR;
457
458         command->minute = rem / IPS_SECSPERMIN;
459         command->second = rem % IPS_SECSPERMIN;
460
461         y = IPS_EPOCH_YEAR;
462         while (days < 0 || days >= (long)year_lengths[yleap = ips_isleap(y)]) {
463                 long    newy;
464
465                 newy = y + days / IPS_DAYSPERNYEAR;
466                 if (days < 0)
467                         --newy;
468                 days -= (newy - y) * IPS_DAYSPERNYEAR +
469                     IPS_LEAPS_THRU_END_OF(newy - 1) -
470                     IPS_LEAPS_THRU_END_OF(y - 1);
471                 y = newy;
472         }
473         command->yearH = y / 100;
474         command->yearL = y % 100;
475         ip = mon_lengths[yleap];
476         for (month = 0; days >= (long)ip[month]; ++month)
477                 days = days - (long)ip[month];
478         command->month = month + 1;
479         command->day = days + 1;
480 }
481
482 static int
483 ips_send_ffdc_reset_cmd(ips_command_t *command)
484 {
485         ips_softc_t *sc = command->sc;
486         ips_adapter_ffdc_cmd *command_struct;
487
488         PRINTF(10, "ips test: got a command, building ffdc reset command\n");
489         command->callback = ips_wakeup_callback;
490         command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
491         command_struct->command = IPS_FFDC_CMD;
492         command_struct->id = command->id;
493         command_struct->reset_count = sc->ffdc_resetcount;
494         command_struct->reset_type  = 0x0;
495         ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
496         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
497             BUS_DMASYNC_PREWRITE);
498         sc->ips_issue_cmd(command);
499         if (command->status.value != IPS_ERROR_STATUS)
500                 ips_timed_wait(command, "ffdc", 0);
501         ips_insert_free_cmd(sc, command);
502         return 0;
503 }
504
505 int
506 ips_ffdc_reset(ips_softc_t *sc)
507 {
508         ips_command_t *command;
509
510         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
511                 device_printf(sc->dev, "ERROR: unable to get a command! "
512                     "can't send ffdc reset!\n");
513                 return 1;
514         }
515         ips_send_ffdc_reset_cmd(command);
516         if (COMMAND_ERROR(&command->status)) {
517                 /*
518                  * apparently some cards may report error status for
519                  * an ffdc reset command, even though it works correctly
520                  * afterwards.  just complain about that and proceed here.
521                  */
522                 device_printf(sc->dev,
523                               "ERROR: ffdc reset command failed(0x%04x)!\n",
524                               command->status.value);
525         }
526         return 0;
527 }
528
529 static void
530 ips_write_nvram(ips_command_t *command)
531 {
532         ips_softc_t *sc = command->sc;
533         ips_rw_nvram_cmd *command_struct;
534         ips_nvram_page5 *nvram;
535
536         /*FIXME check for error */
537         command->callback = ips_wakeup_callback;
538         command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
539         command_struct->command = IPS_RW_NVRAM_CMD;
540         command_struct->id = command->id;
541         command_struct->pagenum = 5;
542         command_struct->rw      = 1;    /* write */
543         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
544             BUS_DMASYNC_POSTREAD);
545         nvram = command->data_buffer;
546         /* retrieve adapter info and save in sc */
547         sc->adapter_type = nvram->adapter_type;
548         strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
549         strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
550         nvram->operating_system = IPS_OS_FREEBSD;
551         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
552             BUS_DMASYNC_PREWRITE);
553         sc->ips_issue_cmd(command);
554 }
555
556 static void
557 ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments, int segnum,
558                         int error)
559 {
560         ips_softc_t *sc;
561         ips_command_t *command = cmdptr;
562         ips_rw_nvram_cmd *command_struct;
563
564         sc = command->sc;
565         if (error) {
566                 command->status.value = IPS_ERROR_STATUS;
567                 ips_insert_free_cmd(sc, command);
568                 printf("ips: error = %d in ips_read_nvram_callback\n", error);
569                 return;
570         }
571         command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
572         command_struct->command = IPS_RW_NVRAM_CMD;
573         command_struct->id = command->id;
574         command_struct->pagenum = 5;
575         command_struct->rw = 0;
576         command_struct->buffaddr = segments[0].ds_addr;
577
578         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
579             BUS_DMASYNC_PREWRITE);
580         bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
581             BUS_DMASYNC_PREREAD);
582         sc->ips_issue_cmd(command);
583 }
584
585 static int
586 ips_read_nvram(ips_command_t *command)
587 {
588         int error = 0;
589         ips_softc_t *sc = command->sc;
590
591         if (bus_dma_tag_create( /* parent    */ sc->adapter_dmatag,
592                                 /* alignemnt */ 1,
593                                 /* boundary  */ 0,
594                                 /* lowaddr   */ BUS_SPACE_MAXADDR_32BIT,
595                                 /* highaddr  */ BUS_SPACE_MAXADDR,
596                                 /* filter    */ NULL,
597                                 /* filterarg */ NULL,
598                                 /* maxsize   */ IPS_NVRAM_PAGE_SIZE,
599                                 /* numsegs   */ 1,
600                                 /* maxsegsize*/ IPS_NVRAM_PAGE_SIZE,
601                                 /* flags     */ 0,
602                                 &command->data_dmatag) != 0) {
603                 printf("ips: can't alloc dma tag for nvram\n");
604                 error = ENOMEM;
605                 goto exit;
606         }
607         if (bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
608             BUS_DMA_NOWAIT, &command->data_dmamap)) {
609                 error = ENOMEM;
610                 goto exit;
611         }
612         command->callback = ips_write_nvram;
613         bus_dmamap_load(command->data_dmatag, command->data_dmamap,
614             command->data_buffer, IPS_NVRAM_PAGE_SIZE, ips_read_nvram_callback,
615             command, BUS_DMA_NOWAIT);
616         if ((command->status.value == IPS_ERROR_STATUS) ||
617             ips_timed_wait(command, "ips", 0) != 0)
618                 error = ETIMEDOUT;
619         if (error == 0) {
620                 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
621                                 BUS_DMASYNC_POSTWRITE);
622         }
623         bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
624 exit:
625         bus_dmamem_free(command->data_dmatag, command->data_buffer,
626                         command->data_dmamap);
627         bus_dma_tag_destroy(command->data_dmatag);
628         ips_insert_free_cmd(sc, command);
629         return error;
630 }
631
632 int
633 ips_update_nvram(ips_softc_t *sc)
634 {
635         ips_command_t *command;
636
637         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
638                 device_printf(sc->dev, "ERROR: unable to get a command! "
639                     "can't update nvram\n");
640                 return 1;
641         }
642         ips_read_nvram(command);
643         if (COMMAND_ERROR(&command->status)) {
644                 device_printf(sc->dev, "ERROR: nvram update command failed!\n");
645                 return 1;
646         }
647         return 0;
648 }
649
650 static int
651 ips_send_config_sync_cmd(ips_command_t *command)
652 {
653         ips_softc_t *sc = command->sc;
654         ips_generic_cmd *command_struct;
655
656         PRINTF(10, "ips test: got a command, building flush command\n");
657         command->callback = ips_wakeup_callback;
658         command_struct = (ips_generic_cmd *)command->command_buffer;
659         command_struct->command = IPS_CONFIG_SYNC_CMD;
660         command_struct->id = command->id;
661         command_struct->reserve2 = IPS_POCL;
662         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
663             BUS_DMASYNC_PREWRITE);
664         sc->ips_issue_cmd(command);
665         if (command->status.value != IPS_ERROR_STATUS)
666                 ips_timed_wait(command, "ipssyn", 0);
667         ips_insert_free_cmd(sc, command);
668         return 0;
669 }
670
671 static int
672 ips_send_error_table_cmd(ips_command_t *command)
673 {
674         ips_softc_t *sc = command->sc;
675         ips_generic_cmd *command_struct;
676
677         PRINTF(10, "ips test: got a command, building errortable command\n");
678         command->callback = ips_wakeup_callback;
679         command_struct = (ips_generic_cmd *)command->command_buffer;
680         command_struct->command = IPS_ERROR_TABLE_CMD;
681         command_struct->id = command->id;
682         command_struct->reserve2 = IPS_CSL;
683         bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
684             BUS_DMASYNC_PREWRITE);
685         sc->ips_issue_cmd(command);
686         if (command->status.value != IPS_ERROR_STATUS)
687                 ips_timed_wait(command, "ipsetc", 0);
688         ips_insert_free_cmd(sc, command);
689         return 0;
690 }
691
692 int
693 ips_clear_adapter(ips_softc_t *sc)
694 {
695         ips_command_t *command;
696
697         device_printf(sc->dev, "syncing config\n");
698         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
699                 device_printf(sc->dev, "ERROR: unable to get a command! "
700                     "can't sync cache!\n");
701                 return 1;
702         }
703         ips_send_config_sync_cmd(command);
704         if (COMMAND_ERROR(&command->status)) {
705                 device_printf(sc->dev, "ERROR: cache sync command failed!\n");
706                 return 1;
707         }
708         device_printf(sc->dev, "clearing error table\n");
709         if (ips_get_free_cmd(sc, &command, IPS_STATIC_FLAG) != 0) {
710                 device_printf(sc->dev, "ERROR: unable to get a command! "
711                     "can't sync cache!\n");
712                 return 1;
713         }
714         ips_send_error_table_cmd(command);
715         if (COMMAND_ERROR(&command->status)) {
716                 device_printf(sc->dev, "ERROR: etable command failed!\n");
717                 return 1;
718         }
719         return 0;
720 }