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