xref: /freebsd/sys/dev/ips/ips_commands.c (revision 3d9368b2d03926ad079a2eb910f1a423df925dd5)
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 "
137 		"pblkno: %lld length: %d, ds_len: %d\n", command->id, segnum,
138 		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 /* Simplified localtime to provide timevalues for ffdc.
438  * Taken from libc/stdtime/localtime.c
439  */
440 void static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
441 {
442 	long	days, rem, y;
443 	int	yleap, *ip, month;
444 	int	year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
445 	int	mon_lengths[2][IPS_MONSPERYEAR] = {
446 		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
447 		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
448 	};
449 
450 	days = sctime / IPS_SECSPERDAY;
451 	rem  = sctime % IPS_SECSPERDAY;
452 
453 	command->hour = rem / IPS_SECSPERHOUR;
454 	rem           = rem % IPS_SECSPERHOUR;
455 
456 	command->minute = rem / IPS_SECSPERMIN;
457 	command->second = rem % IPS_SECSPERMIN;
458 
459 	y = IPS_EPOCH_YEAR;
460 	while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) {
461 		long    newy;
462 
463 		newy = y + days / IPS_DAYSPERNYEAR;
464 		if (days < 0)
465 			--newy;
466 		days -= (newy - y) * IPS_DAYSPERNYEAR +
467 			IPS_LEAPS_THRU_END_OF(newy - 1) -
468 			IPS_LEAPS_THRU_END_OF(y - 1);
469 		y = newy;
470 	}
471 	command->yearH = y / 100;
472 	command->yearL = y % 100;
473 	ip = mon_lengths[yleap];
474 	for(month = 0; days >= (long) ip[month]; ++month)
475 		days = days - (long) ip[month];
476 	command->month = month + 1;
477 	command->day = days + 1;
478 }
479 
480 static int ips_send_ffdc_reset_cmd(ips_command_t *command)
481 {
482 	ips_softc_t *sc = command->sc;
483 	ips_cmd_status_t *status = command->arg;
484 	ips_adapter_ffdc_cmd *command_struct;
485 
486 	PRINTF(10,"ips test: got a command, building ffdc reset command\n");
487 	command->callback = ips_wakeup_callback;
488 	command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
489 	command_struct->command = IPS_FFDC_CMD;
490 	command_struct->id = command->id;
491 	command_struct->reset_count = sc->ffdc_resetcount;
492 	command_struct->reset_type  = 0x80;
493 	ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
494 
495 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
496 			BUS_DMASYNC_PREWRITE);
497 	mtx_lock(&sc->cmd_mtx);
498 	sc->ips_issue_cmd(command);
499 	if (status->value != IPS_ERROR_STATUS)
500 		msleep(status, &sc->cmd_mtx, 0, "ffdc", 0);
501 	mtx_unlock(&sc->cmd_mtx);
502 	ips_insert_free_cmd(sc, command);
503 	return 0;
504 }
505 
506 int ips_ffdc_reset(ips_softc_t *sc)
507 {
508 	ips_cmd_status_t *status;
509 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
510 	if(!status)
511 		return ENOMEM;
512 	if(ips_get_free_cmd(sc, ips_send_ffdc_reset_cmd, status,
513 			    IPS_NOWAIT_FLAG)){
514 		free(status, M_DEVBUF);
515 		device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n");
516 	}
517 	if(COMMAND_ERROR(status)){
518 		device_printf(sc->dev, "ERROR: ffdc reset command failed!\n");
519 	}
520 	free(status, M_DEVBUF);
521 	return 0;
522 }
523 
524 static void ips_write_nvram(ips_command_t *command){
525 	ips_softc_t *sc = command->sc;
526 	ips_rw_nvram_cmd *command_struct;
527 	ips_nvram_page5 *nvram;
528 
529 	/*FIXME check for error */
530 	command->callback = ips_wakeup_callback;
531 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
532 	command_struct->command = IPS_RW_NVRAM_CMD;
533 	command_struct->id = command->id;
534 	command_struct->pagenum = 5;
535 	command_struct->rw	= 1; /*write*/
536 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
537 				BUS_DMASYNC_POSTREAD);
538 	nvram = command->data_buffer;
539 	/* retrieve adapter info and save in sc */
540 	sc->adapter_type = nvram->adapter_type;
541 
542 	strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
543 	strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
544 	nvram->operating_system = IPS_OS_FREEBSD;
545 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
546 			BUS_DMASYNC_PREWRITE);
547 	sc->ips_issue_cmd(command);
548 }
549 
550 static void ips_read_nvram_callback(void *cmdptr, bus_dma_segment_t *segments,int segnum, int error)
551 {
552 	ips_softc_t *sc;
553 	ips_command_t *command = cmdptr;
554 	ips_rw_nvram_cmd *command_struct;
555 	sc = command->sc;
556 	if(error){
557 		ips_cmd_status_t * status = command->arg;
558                 status->value = IPS_ERROR_STATUS;
559 		ips_insert_free_cmd(sc, command);
560 		printf("ips: error = %d in ips_read_nvram_callback\n", error);
561 		return;
562 	}
563 	command_struct = (ips_rw_nvram_cmd *)command->command_buffer;
564 	command_struct->command = IPS_RW_NVRAM_CMD;
565 	command_struct->id = command->id;
566 	command_struct->pagenum = 5;
567 	command_struct->rw = 0;
568 	command_struct->buffaddr = segments[0].ds_addr;
569 
570 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
571 			BUS_DMASYNC_PREWRITE);
572 	bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
573 			BUS_DMASYNC_PREREAD);
574 	sc->ips_issue_cmd(command);
575 }
576 
577 static int ips_read_nvram(ips_command_t *command){
578 	int error = 0;
579 	ips_softc_t *sc = command->sc;
580 	ips_cmd_status_t *status = command->arg;
581 
582 	if (bus_dma_tag_create(	/* parent    */	sc->adapter_dmatag,
583 				/* alignemnt */	1,
584 				/* boundary  */	0,
585 				/* lowaddr   */	BUS_SPACE_MAXADDR_32BIT,
586 				/* highaddr  */	BUS_SPACE_MAXADDR,
587 				/* filter    */	NULL,
588 				/* filterarg */	NULL,
589 				/* maxsize   */	IPS_NVRAM_PAGE_SIZE,
590 				/* numsegs   */	1,
591 				/* maxsegsize*/	IPS_NVRAM_PAGE_SIZE,
592 				/* flags     */	0,
593 				/* lockfunc  */ busdma_lock_mutex,
594 				/* lockarg   */ &Giant,
595 				&command->data_dmatag) != 0) {
596                 printf("ips: can't alloc dma tag for nvram\n");
597 		error = ENOMEM;
598 		goto exit;
599         }
600 	if(bus_dmamem_alloc(command->data_dmatag, &command->data_buffer,
601 	   		    BUS_DMA_NOWAIT, &command->data_dmamap)){
602 		error = ENOMEM;
603 		goto exit;
604 	}
605 	command->callback = ips_write_nvram;
606 	mtx_lock(&sc->cmd_mtx);
607 	bus_dmamap_load(command->data_dmatag, command->data_dmamap,
608 			command->data_buffer,IPS_NVRAM_PAGE_SIZE,
609 			ips_read_nvram_callback, command, BUS_DMA_NOWAIT);
610 	if ((status->value == IPS_ERROR_STATUS) ||
611 	    (msleep(status, &sc->cmd_mtx, 0, "ips", 0) == EWOULDBLOCK))
612 		error = ETIMEDOUT;
613 	mtx_unlock(&sc->cmd_mtx);
614 
615 	if (error == 0) {
616 		bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
617 				BUS_DMASYNC_POSTWRITE);
618 	}
619 	bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
620 
621 exit:
622 	bus_dmamem_free(command->data_dmatag, command->data_buffer,
623 			command->data_dmamap);
624 	bus_dma_tag_destroy(command->data_dmatag);
625 	ips_insert_free_cmd(sc, command);
626 	return error;
627 }
628 
629 int ips_update_nvram(ips_softc_t *sc)
630 {
631 	ips_cmd_status_t *status;
632 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
633 	if(!status)
634 		return ENOMEM;
635 	if(ips_get_free_cmd(sc, ips_read_nvram, status, IPS_NOWAIT_FLAG)){
636 		free(status, M_DEVBUF);
637 		device_printf(sc->dev, "ERROR: unable to get a command! can't update nvram\n");
638 		return 1;
639 	}
640 	if(COMMAND_ERROR(status)){
641 		device_printf(sc->dev, "ERROR: nvram update command failed!\n");
642 	}
643 	free(status, M_DEVBUF);
644 	return 0;
645 
646 
647 }
648 
649 
650 static int ips_send_config_sync_cmd(ips_command_t *command)
651 {
652 	ips_softc_t *sc = command->sc;
653 	ips_cmd_status_t *status = command->arg;
654 	ips_generic_cmd *command_struct;
655 
656 	PRINTF(10,"ips test: got a command, building flush command\n");
657 	command->callback = ips_wakeup_callback;
658 	command_struct = (ips_generic_cmd *)command->command_buffer;
659 	command_struct->command = IPS_CONFIG_SYNC_CMD;
660 	command_struct->id = command->id;
661 	command_struct->reserve2 = IPS_POCL;
662 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
663 			BUS_DMASYNC_PREWRITE);
664 	mtx_lock(&sc->cmd_mtx);
665 	sc->ips_issue_cmd(command);
666 	if (status->value != IPS_ERROR_STATUS)
667 		msleep(status, &sc->cmd_mtx, 0, "ipssyn", 0);
668 	mtx_unlock(&sc->cmd_mtx);
669 	ips_insert_free_cmd(sc, command);
670 	return 0;
671 }
672 
673 static int ips_send_error_table_cmd(ips_command_t *command)
674 {
675 	ips_softc_t *sc = command->sc;
676 	ips_cmd_status_t *status = command->arg;
677 	ips_generic_cmd *command_struct;
678 
679 	PRINTF(10,"ips test: got a command, building errortable command\n");
680 	command->callback = ips_wakeup_callback;
681 	command_struct = (ips_generic_cmd *)command->command_buffer;
682 	command_struct->command = IPS_ERROR_TABLE_CMD;
683 	command_struct->id = command->id;
684 	command_struct->reserve2 = IPS_CSL;
685 	bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
686 			BUS_DMASYNC_PREWRITE);
687 	mtx_lock(&sc->cmd_mtx);
688 	sc->ips_issue_cmd(command);
689 	if (status->value != IPS_ERROR_STATUS)
690 		msleep(status, &sc->cmd_mtx, 0, "ipsetc", 0);
691 	mtx_unlock(&sc->cmd_mtx);
692 	ips_insert_free_cmd(sc, command);
693 	return 0;
694 }
695 
696 
697 int ips_clear_adapter(ips_softc_t *sc)
698 {
699 	ips_cmd_status_t *status;
700 	status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
701 	if(!status)
702 		return ENOMEM;
703 	device_printf(sc->dev, "syncing config\n");
704 	if(ips_get_free_cmd(sc, ips_send_config_sync_cmd, status,
705 			    IPS_NOWAIT_FLAG)){
706 		free(status, M_DEVBUF);
707 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
708 		return 1;
709 	}
710 	if(COMMAND_ERROR(status)){
711 		free(status, M_DEVBUF);
712 		device_printf(sc->dev, "ERROR: cache sync command failed!\n");
713 		return 1;
714 	}
715 
716 	device_printf(sc->dev, "clearing error table\n");
717 	if(ips_get_free_cmd(sc, ips_send_error_table_cmd, status,
718 			    IPS_NOWAIT_FLAG)){
719 		free(status, M_DEVBUF);
720 		device_printf(sc->dev, "ERROR: unable to get a command! can't sync cache!\n");
721 		return 1;
722 	}
723 	if(COMMAND_ERROR(status)){
724 		device_printf(sc->dev, "ERROR: etable command failed!\n");
725 		free(status, M_DEVBUF);
726 		return 1;
727 	}
728 
729 	free(status, M_DEVBUF);
730 	return 0;
731 }
732