ips_commands.c revision 124040
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 124040 2004-01-01 10:22:10Z mbr $");
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	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. */
55static 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
76static 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
145static 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
166void 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 */
182static 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
209static 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
257exit:
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
266int 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 */
290static 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
315static 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
365exit:
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}
374int 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. */
396static 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
418int 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 */
440void 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
480static 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  = 0x0;
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
506int 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
524static 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
550static 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
577static 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
621exit:
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
629int 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
650static 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
673static 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
697int 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