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