xref: /freebsd/sys/dev/ips/ips_commands.c (revision 390e8cc2974df1888369c06339ef8e0e92b312b6)
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 = (uint32_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 				&command->data_dmatag) != 0) {
228                 printf("ips: can't alloc dma tag for adapter status\n");
229 		error = ENOMEM;
230 		goto exit;
231         }
232 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
233 	   BUS_DMA_NOWAIT, &command->data_dmamap)){
234 		error = ENOMEM;
235 		goto exit;
236 	}
237 	command->callback = ips_wakeup_callback;
238 	mtx_lock(&sc->cmd_mtx);
239 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
240 			command->data_buffer,IPS_ADAPTER_INFO_LEN,
241 			ips_adapter_info_callback, command, BUS_DMA_NOWAIT);
242 
243 	if ((status->value == IPS_ERROR_STATUS) ||
244 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 30*hz) == EWOULDBLOCK))
245 		error = ETIMEDOUT;
246 	mtx_unlock(&sc->cmd_mtx);
247 
248 	if (error == 0) {
249 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
250 				BUS_DMASYNC_POSTREAD);
251 		memcpy(&(sc->adapter_info), command->data_buffer,
252 			IPS_ADAPTER_INFO_LEN);
253 	}
254 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
255 
256 exit:
257 	/* I suppose I should clean up my memory allocations */
258 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
259 			command->data_dmamap);
260 	bus_dma_tag_destroy(command->data_dmatag);
261 	ips_insert_free_cmd(sc, command);
262 	return error;
263 }
264 
265 int ips_get_adapter_info(ips_softc_t *sc)
266 {
267 	int error = 0;
268 	ips_cmd_status_t *status;
269 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT);
270 	if(!status)
271 		return ENOMEM;
272 	if(ips_get_free_cmd(sc, ips_send_adapter_info_cmd, status,
273 			    IPS_NOWAIT_FLAG) > 0){
274 		device_printf(sc->dev, "unable to get adapter configuration\n");
275 		free(status, M_DEVBUF);
276 		return ENXIO;
277 	}
278 	if(COMMAND_ERROR(status)){
279 		error = ENXIO;
280 	}
281 	free(status, M_DEVBUF);
282 	return error;
283 }
284 
285 /* Below are a series of functions for sending a drive info request
286  * to the adapter.  The flow order is: get, send, callback. It uses
287  * the generic finish callback at the top of this file.
288  * This can be used to get drive status info from the card */
289 static void ips_drive_info_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
290 {
291 	ips_softc_t *sc;
292 	ips_command_t *command = cmdptr;
293 	ips_drive_cmd *command_struct;
294 	sc = command->sc;
295 	if(error){
296 		ips_cmd_status_t * status = command->arg;
297                 status->value = IPS_ERROR_STATUS;
298 		ips_insert_free_cmd(sc, command);
299 		printf("ips: error = %d in ips_get_drive_info\n", error);
300 		return;
301 	}
302 	command_struct = (ips_drive_cmd *)command->command_buffer;
303 	command_struct->command = IPS_DRIVE_INFO_CMD;
304 	command_struct->id = command->id;
305 	command_struct->buffaddr = segments[0].ds_addr;
306 
307 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
308 			BUS_DMASYNC_PREWRITE);
309 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
310 			BUS_DMASYNC_PREREAD);
311 	sc->ips_issue_cmd(command);
312 }
313 
314 static int ips_send_drive_info_cmd(ips_command_t *command)
315 {
316 	int error = 0;
317 	ips_softc_t *sc = command->sc;
318 	ips_cmd_status_t *status = command->arg;
319 	ips_drive_info_t *driveinfo;
320 
321 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
322 				/* alignemnt */	1,
323 				/* boundary  */	0,
324 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
325 				/* highaddr  */	BUS_SPACE_MAXADDR,
326 				/* filter    */	NULL,
327 				/* filterarg */	NULL,
328 				/* maxsize   */	IPS_DRIVE_INFO_LEN,
329 				/* numsegs   */	1,
330 				/* maxsegsize*/	IPS_DRIVE_INFO_LEN,
331 				/* flags     */	0,
332 				&command->data_dmatag) != 0) {
333                 printf("ips: can't alloc dma tag for drive status\n");
334 		error = ENOMEM;
335 		goto exit;
336         }
337 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
338 	   		    BUS_DMA_NOWAIT, &command->data_dmamap)){
339 		error = ENOMEM;
340 		goto exit;
341 	}
342 	command->callback = ips_wakeup_callback;
343 	mtx_lock(&sc->cmd_mtx);
344 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
345 			command->data_buffer,IPS_DRIVE_INFO_LEN,
346 			ips_drive_info_callback, command, BUS_DMA_NOWAIT);
347 	if ((status->value == IPS_ERROR_STATUS) ||
348 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 10*hz) == EWOULDBLOCK))
349 		error = ETIMEDOUT;
350 	mtx_unlock(&sc->cmd_mtx);
351 
352 	if (error == 0) {
353 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
354 				BUS_DMASYNC_POSTREAD);
355 		driveinfo = command->data_buffer;
356 		memcpy(sc->drives, driveinfo->drives, sizeof(ips_drive_t) * 8);
357 		sc->drivecount = driveinfo->drivecount;
358 		device_printf(sc->dev, "logical drives: %d\n",sc->drivecount);
359 	}
360 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
361 
362 exit:
363 	/* I suppose I should clean up my memory allocations */
364 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
365 			command->data_dmamap);
366 	bus_dma_tag_destroy(command->data_dmatag);
367 	ips_insert_free_cmd(sc, command);
368 	return error;
369 
370 }
371 int ips_get_drive_info(ips_softc_t *sc)
372 {
373 	int error = 0;
374 	ips_cmd_status_t *status;
375 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT);
376 	if(!status)
377 		return ENOMEM;
378 	if(ips_get_free_cmd(sc, ips_send_drive_info_cmd, status,
379 			    IPS_NOWAIT_FLAG) > 0){
380 		free(status, M_DEVBUF);
381 		device_printf(sc->dev, "unable to get drive configuration\n");
382 		return ENXIO;
383 	}
384 	if(COMMAND_ERROR(status)){
385 		error = ENXIO;
386 	}
387 	free(status, M_DEVBUF);
388 	return error;
389 }
390 
391 /* Below is a pair of functions for making sure data is safely
392  * on disk by flushing the adapter's cache. */
393 static int ips_send_flush_cache_cmd(ips_command_t *command)
394 {
395 	ips_softc_t *sc = command->sc;
396 	ips_cmd_status_t *status = command->arg;
397 	ips_generic_cmd *command_struct;
398 
399 	PRINTF(10,"ips test: got a command, building flush command\n");
400 	command->callback = ips_wakeup_callback;
401 	command_struct = (ips_generic_cmd *)command->command_buffer;
402 	command_struct->command = IPS_CACHE_FLUSH_CMD;
403 	command_struct->id = command->id;
404 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
405 			BUS_DMASYNC_PREWRITE);
406 	mtx_lock(&sc->cmd_mtx);
407 	sc->ips_issue_cmd(command);
408 	if (status->value != IPS_ERROR_STATUS)
409 		msleep(status, &sc->cmd_mtx, 0, "flush2", 0);
410 	mtx_unlock(&sc->cmd_mtx);
411 	ips_insert_free_cmd(sc, command);
412 	return 0;
413 }
414 
415 int ips_flush_cache(ips_softc_t *sc)
416 {
417 	ips_cmd_status_t *status;
418 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT);
419 	if(!status)
420 		return ENOMEM;
421 	device_printf(sc->dev, "flushing cache\n");
422 	if(ips_get_free_cmd(sc, ips_send_flush_cache_cmd, status,
423 			    IPS_NOWAIT_FLAG)){
424 		free(status, M_DEVBUF);
425 		device_printf(sc->dev, "ERROR: unable to get a command! can't flush cache!\n");
426 	}
427 	if(COMMAND_ERROR(status)){
428 		device_printf(sc->dev, "ERROR: cache flush command failed!\n");
429 	}
430 	free(status, M_DEVBUF);
431 	return 0;
432 }
433 
434 static void ips_write_nvram(ips_command_t *command){
435 	ips_softc_t *sc = command->sc;
436 	ips_rw_nvram_cmd *command_struct;
437 	ips_nvram_page5 *nvram;
438 
439 	/*FIXME check for error */
440 	command->callback = ips_wakeup_callback;
441 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
442 	command_struct->command = IPS_RW_NVRAM_CMD;
443 	command_struct->id = command->id;
444 	command_struct->pagenum = 5;
445 	command_struct->rw	= 1; /*write*/
446 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
447 				BUS_DMASYNC_POSTREAD);
448 	nvram = command->data_buffer;
449 	strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
450 	strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
451 	nvram->operating_system = IPS_OS_FREEBSD;
452 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
453 			BUS_DMASYNC_PREWRITE);
454 	sc->ips_issue_cmd(command);
455 }
456 
457 static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
458 {
459 	ips_softc_t *sc;
460 	ips_command_t *command = cmdptr;
461 	ips_rw_nvram_cmd *command_struct;
462 	sc = command->sc;
463 	if(error){
464 		ips_cmd_status_t * status = command->arg;
465                 status->value = IPS_ERROR_STATUS;
466 		ips_insert_free_cmd(sc, command);
467 		printf("ips: error = %d in ips_read_nvram_callback\n", error);
468 		return;
469 	}
470 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
471 	command_struct->command = IPS_RW_NVRAM_CMD;
472 	command_struct->id = command->id;
473 	command_struct->pagenum = 5;
474 	command_struct->rw = 0;
475 	command_struct->buffaddr = segments[0].ds_addr;
476 
477 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
478 			BUS_DMASYNC_PREWRITE);
479 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
480 			BUS_DMASYNC_PREREAD);
481 	sc->ips_issue_cmd(command);
482 }
483 
484 static int ips_read_nvram(ips_command_t *command){
485 	int error = 0;
486 	ips_softc_t *sc = command->sc;
487 	ips_cmd_status_t *status = command->arg;
488 
489 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
490 				/* alignemnt */	1,
491 				/* boundary  */	0,
492 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
493 				/* highaddr  */	BUS_SPACE_MAXADDR,
494 				/* filter    */	NULL,
495 				/* filterarg */	NULL,
496 				/* maxsize   */	IPS_NVRAM_PAGE_SIZE,
497 				/* numsegs   */	1,
498 				/* maxsegsize*/	IPS_NVRAM_PAGE_SIZE,
499 				/* flags     */	0,
500 				&command->data_dmatag) != 0) {
501                 printf("ips: can't alloc dma tag for nvram\n");
502 		error = ENOMEM;
503 		goto exit;
504         }
505 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
506 	   		    BUS_DMA_NOWAIT, &command->data_dmamap)){
507 		error = ENOMEM;
508 		goto exit;
509 	}
510 	command->callback = ips_write_nvram;
511 	mtx_lock(&sc->cmd_mtx);
512 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
513 			command->data_buffer,IPS_NVRAM_PAGE_SIZE,
514 			ips_read_nvram_callback, command, BUS_DMA_NOWAIT);
515 	if ((status->value == IPS_ERROR_STATUS) ||
516 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 0) == EWOULDBLOCK))
517 		error = ETIMEDOUT;
518 	mtx_unlock(&sc->cmd_mtx);
519 
520 	if (error == 0) {
521 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
522 				BUS_DMASYNC_POSTWRITE);
523 	}
524 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
525 
526 exit:
527 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
528 			command->data_dmamap);
529 	bus_dma_tag_destroy(command->data_dmatag);
530 	ips_insert_free_cmd(sc, command);
531 	return error;
532 }
533 
534 int ips_update_nvram(ips_softc_t *sc)
535 {
536 	ips_cmd_status_t *status;
537 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT);
538 	if(!status)
539 		return ENOMEM;
540 	if(ips_get_free_cmd(sc, ips_read_nvram, status, IPS_NOWAIT_FLAG)){
541 		free(status, M_DEVBUF);
542 		device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n");
543 		return 1;
544 	}
545 	if(COMMAND_ERROR(status)){
546 		device_printf(sc->dev, "ERROR: nvram update command failed!\n");
547 	}
548 	free(status, M_DEVBUF);
549 	return 0;
550 
551 
552 }
553 
554 
555 static int ips_send_config_sync_cmd(ips_command_t *command)
556 {
557 	ips_softc_t *sc = command->sc;
558 	ips_cmd_status_t *status = command->arg;
559 	ips_generic_cmd *command_struct;
560 
561 	PRINTF(10,"ips test: got a command, building flush command\n");
562 	command->callback = ips_wakeup_callback;
563 	command_struct = (ips_generic_cmd *)command->command_buffer;
564 	command_struct->command = IPS_CONFIG_SYNC_CMD;
565 	command_struct->id = command->id;
566 	command_struct->reserve2 = IPS_POCL;
567 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
568 			BUS_DMASYNC_PREWRITE);
569 	mtx_lock(&sc->cmd_mtx);
570 	sc->ips_issue_cmd(command);
571 	if (status->value != IPS_ERROR_STATUS)
572 		msleep(status, &sc->cmd_mtx, 0, "ipssyn", 0);
573 	mtx_unlock(&sc->cmd_mtx);
574 	ips_insert_free_cmd(sc, command);
575 	return 0;
576 }
577 
578 static int ips_send_error_table_cmd(ips_command_t *command)
579 {
580 	ips_softc_t *sc = command->sc;
581 	ips_cmd_status_t *status = command->arg;
582 	ips_generic_cmd *command_struct;
583 
584 	PRINTF(10,"ips test: got a command, building errortable command\n");
585 	command->callback = ips_wakeup_callback;
586 	command_struct = (ips_generic_cmd *)command->command_buffer;
587 	command_struct->command = IPS_ERROR_TABLE_CMD;
588 	command_struct->id = command->id;
589 	command_struct->reserve2 = IPS_CSL;
590 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
591 			BUS_DMASYNC_PREWRITE);
592 	mtx_lock(&sc->cmd_mtx);
593 	sc->ips_issue_cmd(command);
594 	if (status->value != IPS_ERROR_STATUS)
595 		msleep(status, &sc->cmd_mtx, 0, "ipsetc", 0);
596 	mtx_unlock(&sc->cmd_mtx);
597 	ips_insert_free_cmd(sc, command);
598 	return 0;
599 }
600 
601 
602 int ips_clear_adapter(ips_softc_t *sc)
603 {
604 	ips_cmd_status_t *status;
605 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT);
606 	if(!status)
607 		return ENOMEM;
608 	device_printf(sc->dev, "syncing config\n");
609 	if(ips_get_free_cmd(sc, ips_send_config_sync_cmd, status,
610 			    IPS_NOWAIT_FLAG)){
611 		free(status, M_DEVBUF);
612 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
613 		return 1;
614 	}
615 	if(COMMAND_ERROR(status)){
616 		free(status, M_DEVBUF);
617 		device_printf(sc->dev, "ERROR: cache sync command failed!\n");
618 		return 1;
619 	}
620 
621 	device_printf(sc->dev, "clearing error table\n");
622 	if(ips_get_free_cmd(sc, ips_send_error_table_cmd, status,
623 			    IPS_NOWAIT_FLAG)){
624 		free(status, M_DEVBUF);
625 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
626 		return 1;
627 	}
628 	if(COMMAND_ERROR(status)){
629 		device_printf(sc->dev, "ERROR: etable command failed!\n");
630 		free(status, M_DEVBUF);
631 		return 1;
632 	}
633 
634 	free(status, M_DEVBUF);
635 	return 0;
636 }
637