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