xref: /freebsd/sys/dev/ips/ips_commands.c (revision e0c27215058b5786c78fcfb3963eebe61a989511)
1 /*-
2  * Copyright (c) 2002 Adaptec Inc.
3  * All rights reserved.
4  *
5  * Written by: David Jeffery
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30 
31 
32 #include <dev/ips/ips.h>
33 
34 /*
35  * This is an interrupt callback.  It is called from
36  * interrupt context when the adapter has completed the
37  * command.  This very generic callback simply stores
38  * the command's return value in command->arg and wake's
39  * up anyone waiting on the command.
40  */
41 static void ips_wakeup_callback(ips_command_t *command)
42 {
43 	ips_cmd_status_t *status;
44 	status = command->arg;
45 	status->value = command->status.value;
46 	bus_dmamap_sync(command->sc->command_dmatag, command->command_dmamap,
47 			BUS_DMASYNC_POSTWRITE);
48 	mtx_lock(&command->sc->cmd_mtx);
49 	wakeup(status);
50 	mtx_unlock(&command->sc->cmd_mtx);
51 }
52 /* Below are a series of functions for sending an IO request
53  * to the adapter.  The flow order is: start, send, callback, finish.
54  * The caller must have already assembled an iorequest struct to hold
55  * the details of the IO request. */
56 static void ips_io_request_finish(ips_command_t *command)
57 {
58 
59 	struct bio *iobuf = command->arg;
60 	if(ips_read_request(iobuf)) {
61 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
62 				BUS_DMASYNC_POSTREAD);
63 	} else {
64 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
65 				BUS_DMASYNC_POSTWRITE);
66 	}
67 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
68 	bus_dmamap_destroy(command->data_dmatag, command->data_dmamap);
69 	if(COMMAND_ERROR(&command->status)){
70 		iobuf->bio_flags |=BIO_ERROR;
71 		iobuf->bio_error = EIO;
72 	}
73 	ips_insert_free_cmd(command->sc, command);
74 	ipsd_finish(iobuf);
75 }
76 
77 static void ips_io_request_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
78 {
79 	ips_softc_t *sc;
80 	ips_command_t *command = cmdptr;
81 	ips_sg_element_t *sg_list;
82 	ips_io_cmd *command_struct;
83 	struct bio *iobuf = command->arg;
84 	int i, length = 0;
85 	u_int8_t cmdtype;
86 
87 	sc = command->sc;
88 	if(error){
89 		printf("ips: error = %d in ips_sg_request_callback\n", error);
90 		bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
91 		bus_dmamap_destroy(command->data_dmatag, command->data_dmamap);
92 		iobuf->bio_flags |= BIO_ERROR;
93 		iobuf->bio_error = ENOMEM;
94 		ips_insert_free_cmd(sc, command);
95 		ipsd_finish(iobuf);
96 		return;
97 	}
98 	command_struct = (ips_io_cmd *)command->command_buffer;
99 	command_struct->id = command->id;
100 	command_struct->drivenum = (uintptr_t)iobuf->bio_driver1;
101 	if(segnum != 1){
102 		if(ips_read_request(iobuf))
103 			cmdtype = IPS_SG_READ_CMD;
104 		else
105 			cmdtype = IPS_SG_WRITE_CMD;
106 		command_struct->segnum = segnum;
107 		sg_list = (ips_sg_element_t *)((u_int8_t *)
108 			   command->command_buffer + IPS_COMMAND_LEN);
109 		for(i = 0; i < segnum; i++){
110 			sg_list[i].addr = segments[i].ds_addr;
111 			sg_list[i].len = segments[i].ds_len;
112 			length += segments[i].ds_len;
113 		}
114 		command_struct->buffaddr =
115 	    	    (u_int32_t)command->command_phys_addr + IPS_COMMAND_LEN;
116 	} else {
117 		if(ips_read_request(iobuf))
118 			cmdtype = IPS_READ_CMD;
119 		else
120 			cmdtype = IPS_WRITE_CMD;
121 		command_struct->buffaddr = segments[0].ds_addr;
122 		length = segments[0].ds_len;
123 	}
124 	command_struct->command = cmdtype;
125 	command_struct->lba = iobuf->bio_pblkno;
126 	length = (length + IPS_BLKSIZE - 1)/IPS_BLKSIZE;
127 	command_struct->length = length;
128 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
129 			BUS_DMASYNC_PREWRITE);
130 	if(ips_read_request(iobuf)) {
131 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
132 				BUS_DMASYNC_PREREAD);
133 	} else {
134 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
135 				BUS_DMASYNC_PREWRITE);
136 	}
137 	PRINTF(10, "ips test: command id: %d segments: %d blkno: %lld "
138 		"pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
139 		iobuf->bio_blkno, iobuf->bio_pblkno,
140 		length, segments[0].ds_len);
141 
142 	sc->ips_issue_cmd(command);
143 	return;
144 }
145 
146 static int ips_send_io_request(ips_command_t *command)
147 {
148 	ips_softc_t *sc = command->sc;
149 	struct bio *iobuf = command->arg;
150 	command->data_dmatag = sc->sg_dmatag;
151 	if(bus_dmamap_create(command->data_dmatag, 0, &command->data_dmamap)){
152 		device_printf(sc->dev, "dmamap failed\n");
153 		iobuf->bio_flags |= BIO_ERROR;
154 		iobuf->bio_error = ENOMEM;
155 		ips_insert_free_cmd(sc, command);
156 		ipsd_finish(iobuf);
157 		return 0;
158 	}
159 	command->callback = ips_io_request_finish;
160 	PRINTF(10, "ips test: : bcount %ld\n", iobuf->bio_bcount);
161 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
162 			iobuf->bio_data, iobuf->bio_bcount,
163 			ips_io_request_callback, command, 0);
164 	return 0;
165 }
166 
167 void ips_start_io_request(ips_softc_t *sc, struct bio *iobuf)
168 {
169 	if(ips_get_free_cmd(sc, ips_send_io_request, iobuf, 0)){
170 		device_printf(sc->dev, "no mem for command slots!\n");
171 		iobuf->bio_flags |= BIO_ERROR;
172 		iobuf->bio_error = ENOMEM;
173 		ipsd_finish(iobuf);
174 		return;
175 	}
176 	return;
177 }
178 
179 /* Below are a series of functions for sending an adapter info request
180  * to the adapter.  The flow order is: get, send, callback. It uses
181  * the generic finish callback at the top of this file.
182  * This can be used to get configuration/status info from the card */
183 static void ips_adapter_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
184 {
185 	ips_softc_t *sc;
186 	ips_command_t *command = cmdptr;
187 	ips_adapter_info_cmd *command_struct;
188 	sc = command->sc;
189 	if(error){
190 		ips_cmd_status_t * status = command->arg;
191 		status->value = IPS_ERROR_STATUS; /* a lovely error value */
192 		ips_insert_free_cmd(sc, command);
193 		printf("ips: error = %d in ips_get_adapter_info\n", error);
194 		return;
195 	}
196 	command_struct = (ips_adapter_info_cmd *)command->command_buffer;
197 	command_struct->command = IPS_ADAPTER_INFO_CMD;
198 	command_struct->id = command->id;
199 	command_struct->buffaddr = segments[0].ds_addr;
200 
201 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
202 			BUS_DMASYNC_PREWRITE);
203 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
204 			BUS_DMASYNC_PREREAD);
205 	sc->ips_issue_cmd(command);
206 }
207 
208 
209 
210 static int ips_send_adapter_info_cmd(ips_command_t *command)
211 {
212 	int error = 0;
213 	ips_softc_t *sc = command->sc;
214 	ips_cmd_status_t *status = command->arg;
215 
216 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
217 				/* alignemnt */	1,
218 				/* boundary  */	0,
219 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
220 				/* highaddr  */	BUS_SPACE_MAXADDR,
221 				/* filter    */	NULL,
222 				/* filterarg */	NULL,
223 				/* maxsize   */	IPS_ADAPTER_INFO_LEN,
224 				/* numsegs   */	1,
225 				/* maxsegsize*/	IPS_ADAPTER_INFO_LEN,
226 				/* flags     */	0,
227 				/* lockfunc  */ busdma_lock_mutex,
228 				/* lockarg   */ &Giant,
229 				&command->data_dmatag) != 0) {
230                 printf("ips: can't alloc dma tag for adapter status\n");
231 		error = ENOMEM;
232 		goto exit;
233         }
234 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
235 	   BUS_DMA_NOWAIT, &command->data_dmamap)){
236 		error = ENOMEM;
237 		goto exit;
238 	}
239 	command->callback = ips_wakeup_callback;
240 	mtx_lock(&sc->cmd_mtx);
241 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
242 			command->data_buffer,IPS_ADAPTER_INFO_LEN,
243 			ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
244 
245 	if ((status->value == IPS_ERROR_STATUS) ||
246 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 30*hz) == EWOULDBLOCK))
247 		error = ETIMEDOUT;
248 	mtx_unlock(&sc->cmd_mtx);
249 
250 	if (error == 0) {
251 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
252 				BUS_DMASYNC_POSTREAD);
253 		memcpy(&(sc->adapter_info), command->data_buffer,
254 			IPS_ADAPTER_INFO_LEN);
255 	}
256 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
257 
258 exit:
259 	/* I suppose I should clean up my memory allocations */
260 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
261 			command->data_dmamap);
262 	bus_dma_tag_destroy(command->data_dmatag);
263 	ips_insert_free_cmd(sc, command);
264 	return error;
265 }
266 
267 int ips_get_adapter_info(ips_softc_t *sc)
268 {
269 	int error = 0;
270 	ips_cmd_status_t *status;
271 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
272 	if(!status)
273 		return ENOMEM;
274 	if(ips_get_free_cmd(sc, ips_send_adapter_info_cmd, status,
275 			    IPS_NOWAIT_FLAG) > 0){
276 		device_printf(sc->dev, "unable to get adapter configuration\n");
277 		free(status, M_DEVBUF);
278 		return ENXIO;
279 	}
280 	if (COMMAND_ERROR(status)){
281 		error = ENXIO;
282 	}
283 	free(status, M_DEVBUF);
284 	return error;
285 }
286 
287 /* Below are a series of functions for sending a drive info request
288  * to the adapter.  The flow order is: get, send, callback. It uses
289  * the generic finish callback at the top of this file.
290  * This can be used to get drive status info from the card */
291 static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
292 {
293 	ips_softc_t *sc;
294 	ips_command_t *command = cmdptr;
295 	ips_drive_cmd *command_struct;
296 	sc = command->sc;
297 	if(error){
298 		ips_cmd_status_t * status = command->arg;
299                 status->value = IPS_ERROR_STATUS;
300 		ips_insert_free_cmd(sc, command);
301 		printf("ips: error = %d in ips_get_drive_info\n", error);
302 		return;
303 	}
304 	command_struct = (ips_drive_cmd *)command->command_buffer;
305 	command_struct->command = IPS_DRIVE_INFO_CMD;
306 	command_struct->id = command->id;
307 	command_struct->buffaddr = segments[0].ds_addr;
308 
309 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
310 			BUS_DMASYNC_PREWRITE);
311 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
312 			BUS_DMASYNC_PREREAD);
313 	sc->ips_issue_cmd(command);
314 }
315 
316 static int ips_send_drive_info_cmd(ips_command_t *command)
317 {
318 	int error = 0;
319 	ips_softc_t *sc = command->sc;
320 	ips_cmd_status_t *status = command->arg;
321 	ips_drive_info_t *driveinfo;
322 
323 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
324 				/* alignemnt */	1,
325 				/* boundary  */	0,
326 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
327 				/* highaddr  */	BUS_SPACE_MAXADDR,
328 				/* filter    */	NULL,
329 				/* filterarg */	NULL,
330 				/* maxsize   */	IPS_DRIVE_INFO_LEN,
331 				/* numsegs   */	1,
332 				/* maxsegsize*/	IPS_DRIVE_INFO_LEN,
333 				/* flags     */	0,
334 				/* lockfunc  */ busdma_lock_mutex,
335 				/* lockarg   */ &Giant,
336 				&command->data_dmatag) != 0) {
337                 printf("ips: can't alloc dma tag for drive status\n");
338 		error = ENOMEM;
339 		goto exit;
340         }
341 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
342 	   		    BUS_DMA_NOWAIT, &command->data_dmamap)){
343 		error = ENOMEM;
344 		goto exit;
345 	}
346 	command->callback = ips_wakeup_callback;
347 	mtx_lock(&sc->cmd_mtx);
348 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
349 			command->data_buffer,IPS_DRIVE_INFO_LEN,
350 			ips_drive_info_callback, command, BUS_DMA_NOWAIT);
351 	if ((status->value == IPS_ERROR_STATUS) ||
352 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 10*hz) == EWOULDBLOCK))
353 		error = ETIMEDOUT;
354 	mtx_unlock(&sc->cmd_mtx);
355 
356 	if (error == 0) {
357 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
358 				BUS_DMASYNC_POSTREAD);
359 		driveinfo = command->data_buffer;
360 		memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
361 		sc->drivecount = driveinfo->drivecount;
362 		device_printf(sc->dev, "logical drives: %d\n",sc->drivecount);
363 	}
364 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
365 
366 exit:
367 	/* I suppose I should clean up my memory allocations */
368 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
369 			command->data_dmamap);
370 	bus_dma_tag_destroy(command->data_dmatag);
371 	ips_insert_free_cmd(sc, command);
372 	return error;
373 
374 }
375 int ips_get_drive_info(ips_softc_t *sc)
376 {
377 	int error = 0;
378 	ips_cmd_status_t *status;
379 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
380 	if(!status)
381 		return ENOMEM;
382 	if(ips_get_free_cmd(sc, ips_send_drive_info_cmd, status,
383 			    IPS_NOWAIT_FLAG) > 0){
384 		free(status, M_DEVBUF);
385 		device_printf(sc->dev, "unable to get drive configuration\n");
386 		return ENXIO;
387 	}
388 	if(COMMAND_ERROR(status)){
389 		error = ENXIO;
390 	}
391 	free(status, M_DEVBUF);
392 	return error;
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 static int ips_send_flush_cache_cmd(ips_command_t *command)
398 {
399 	ips_softc_t *sc = command->sc;
400 	ips_cmd_status_t *status = command->arg;
401 	ips_generic_cmd *command_struct;
402 
403 	PRINTF(10,"ips test: got a command, building flush command\n");
404 	command->callback = ips_wakeup_callback;
405 	command_struct = (ips_generic_cmd *)command->command_buffer;
406 	command_struct->command = IPS_CACHE_FLUSH_CMD;
407 	command_struct->id = command->id;
408 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
409 			BUS_DMASYNC_PREWRITE);
410 	mtx_lock(&sc->cmd_mtx);
411 	sc->ips_issue_cmd(command);
412 	if (status->value != IPS_ERROR_STATUS)
413 		msleep(status, &sc->cmd_mtx, 0, "flush2", 0);
414 	mtx_unlock(&sc->cmd_mtx);
415 	ips_insert_free_cmd(sc, command);
416 	return 0;
417 }
418 
419 int ips_flush_cache(ips_softc_t *sc)
420 {
421 	ips_cmd_status_t *status;
422 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
423 	if(!status)
424 		return ENOMEM;
425 	device_printf(sc->dev, "flushing cache\n");
426 	if(ips_get_free_cmd(sc, ips_send_flush_cache_cmd, status,
427 			    IPS_NOWAIT_FLAG)){
428 		free(status, M_DEVBUF);
429 		device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n");
430 	}
431 	if(COMMAND_ERROR(status)){
432 		device_printf(sc->dev, "ERROR: cache flush command failed!\n");
433 	}
434 	free(status, M_DEVBUF);
435 	return 0;
436 }
437 
438 static void ips_write_nvram(ips_command_t *command){
439 	ips_softc_t *sc = command->sc;
440 	ips_rw_nvram_cmd *command_struct;
441 	ips_nvram_page5 *nvram;
442 
443 	/*FIXME check for error */
444 	command->callback = ips_wakeup_callback;
445 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
446 	command_struct->command = IPS_RW_NVRAM_CMD;
447 	command_struct->id = command->id;
448 	command_struct->pagenum = 5;
449 	command_struct->rw	= 1; /*write*/
450 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
451 				BUS_DMASYNC_POSTREAD);
452 	nvram = command->data_buffer;
453 	strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
454 	strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
455 	nvram->operating_system = IPS_OS_FREEBSD;
456 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
457 			BUS_DMASYNC_PREWRITE);
458 	sc->ips_issue_cmd(command);
459 }
460 
461 static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
462 {
463 	ips_softc_t *sc;
464 	ips_command_t *command = cmdptr;
465 	ips_rw_nvram_cmd *command_struct;
466 	sc = command->sc;
467 	if(error){
468 		ips_cmd_status_t * status = command->arg;
469                 status->value = IPS_ERROR_STATUS;
470 		ips_insert_free_cmd(sc, command);
471 		printf("ips: error = %d in ips_read_nvram_callback\n", error);
472 		return;
473 	}
474 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
475 	command_struct->command = IPS_RW_NVRAM_CMD;
476 	command_struct->id = command->id;
477 	command_struct->pagenum = 5;
478 	command_struct->rw = 0;
479 	command_struct->buffaddr = segments[0].ds_addr;
480 
481 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
482 			BUS_DMASYNC_PREWRITE);
483 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
484 			BUS_DMASYNC_PREREAD);
485 	sc->ips_issue_cmd(command);
486 }
487 
488 static int ips_read_nvram(ips_command_t *command){
489 	int error = 0;
490 	ips_softc_t *sc = command->sc;
491 	ips_cmd_status_t *status = command->arg;
492 
493 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
494 				/* alignemnt */	1,
495 				/* boundary  */	0,
496 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
497 				/* highaddr  */	BUS_SPACE_MAXADDR,
498 				/* filter    */	NULL,
499 				/* filterarg */	NULL,
500 				/* maxsize   */	IPS_NVRAM_PAGE_SIZE,
501 				/* numsegs   */	1,
502 				/* maxsegsize*/	IPS_NVRAM_PAGE_SIZE,
503 				/* flags     */	0,
504 				/* lockfunc  */ busdma_lock_mutex,
505 				/* lockarg   */ &Giant,
506 				&command->data_dmatag) != 0) {
507                 printf("ips: can't alloc dma tag for nvram\n");
508 		error = ENOMEM;
509 		goto exit;
510         }
511 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
512 	   		    BUS_DMA_NOWAIT, &command->data_dmamap)){
513 		error = ENOMEM;
514 		goto exit;
515 	}
516 	command->callback = ips_write_nvram;
517 	mtx_lock(&sc->cmd_mtx);
518 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
519 			command->data_buffer,IPS_NVRAM_PAGE_SIZE,
520 			ips_read_nvram_callback, command, BUS_DMA_NOWAIT);
521 	if ((status->value == IPS_ERROR_STATUS) ||
522 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 0) == EWOULDBLOCK))
523 		error = ETIMEDOUT;
524 	mtx_unlock(&sc->cmd_mtx);
525 
526 	if (error == 0) {
527 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
528 				BUS_DMASYNC_POSTWRITE);
529 	}
530 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
531 
532 exit:
533 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
534 			command->data_dmamap);
535 	bus_dma_tag_destroy(command->data_dmatag);
536 	ips_insert_free_cmd(sc, command);
537 	return error;
538 }
539 
540 int ips_update_nvram(ips_softc_t *sc)
541 {
542 	ips_cmd_status_t *status;
543 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
544 	if(!status)
545 		return ENOMEM;
546 	if(ips_get_free_cmd(sc, ips_read_nvram, status, IPS_NOWAIT_FLAG)){
547 		free(status, M_DEVBUF);
548 		device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n");
549 		return 1;
550 	}
551 	if(COMMAND_ERROR(status)){
552 		device_printf(sc->dev, "ERROR: nvram update command failed!\n");
553 	}
554 	free(status, M_DEVBUF);
555 	return 0;
556 
557 
558 }
559 
560 
561 static int ips_send_config_sync_cmd(ips_command_t *command)
562 {
563 	ips_softc_t *sc = command->sc;
564 	ips_cmd_status_t *status = command->arg;
565 	ips_generic_cmd *command_struct;
566 
567 	PRINTF(10,"ips test: got a command, building flush command\n");
568 	command->callback = ips_wakeup_callback;
569 	command_struct = (ips_generic_cmd *)command->command_buffer;
570 	command_struct->command = IPS_CONFIG_SYNC_CMD;
571 	command_struct->id = command->id;
572 	command_struct->reserve2 = IPS_POCL;
573 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
574 			BUS_DMASYNC_PREWRITE);
575 	mtx_lock(&sc->cmd_mtx);
576 	sc->ips_issue_cmd(command);
577 	if (status->value != IPS_ERROR_STATUS)
578 		msleep(status, &sc->cmd_mtx, 0, "ipssyn", 0);
579 	mtx_unlock(&sc->cmd_mtx);
580 	ips_insert_free_cmd(sc, command);
581 	return 0;
582 }
583 
584 static int ips_send_error_table_cmd(ips_command_t *command)
585 {
586 	ips_softc_t *sc = command->sc;
587 	ips_cmd_status_t *status = command->arg;
588 	ips_generic_cmd *command_struct;
589 
590 	PRINTF(10,"ips test: got a command, building errortable command\n");
591 	command->callback = ips_wakeup_callback;
592 	command_struct = (ips_generic_cmd *)command->command_buffer;
593 	command_struct->command = IPS_ERROR_TABLE_CMD;
594 	command_struct->id = command->id;
595 	command_struct->reserve2 = IPS_CSL;
596 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
597 			BUS_DMASYNC_PREWRITE);
598 	mtx_lock(&sc->cmd_mtx);
599 	sc->ips_issue_cmd(command);
600 	if (status->value != IPS_ERROR_STATUS)
601 		msleep(status, &sc->cmd_mtx, 0, "ipsetc", 0);
602 	mtx_unlock(&sc->cmd_mtx);
603 	ips_insert_free_cmd(sc, command);
604 	return 0;
605 }
606 
607 
608 int ips_clear_adapter(ips_softc_t *sc)
609 {
610 	ips_cmd_status_t *status;
611 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
612 	if(!status)
613 		return ENOMEM;
614 	device_printf(sc->dev, "syncing config\n");
615 	if(ips_get_free_cmd(sc, ips_send_config_sync_cmd, status,
616 			    IPS_NOWAIT_FLAG)){
617 		free(status, M_DEVBUF);
618 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
619 		return 1;
620 	}
621 	if(COMMAND_ERROR(status)){
622 		free(status, M_DEVBUF);
623 		device_printf(sc->dev, "ERROR: cache sync command failed!\n");
624 		return 1;
625 	}
626 
627 	device_printf(sc->dev, "clearing error table\n");
628 	if(ips_get_free_cmd(sc, ips_send_error_table_cmd, status,
629 			    IPS_NOWAIT_FLAG)){
630 		free(status, M_DEVBUF);
631 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
632 		return 1;
633 	}
634 	if(COMMAND_ERROR(status)){
635 		device_printf(sc->dev, "ERROR: etable command failed!\n");
636 		free(status, M_DEVBUF);
637 		return 1;
638 	}
639 
640 	free(status, M_DEVBUF);
641 	return 0;
642 }
643