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