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