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