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: releng/5.3/sys/dev/ips/ips_commands.c 130481 2004-06-14 18:19:05Z jdp $");
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 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. */
53 static 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
74 static 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
143 static 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
164 void 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 */
189 static 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
216 static 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
262 exit:
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
271 int 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_IPSBUF, 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_IPSBUF);
282 return ENXIO;
283 }
284 if (COMMAND_ERROR(status)){
285 error = ENXIO;
286 }
287 free(status, M_IPSBUF);
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 */
295 static 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
320 static 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
368 exit:
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 }
377 int 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_IPSBUF, 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_IPSBUF);
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_IPSBUF);
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. */
399 static 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
419 int ips_flush_cache(ips_softc_t *sc)
420 {
421 ips_cmd_status_t *status;
422 status = malloc(sizeof(ips_cmd_status_t), M_IPSBUF, 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_IPSBUF);
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_IPSBUF);
435 return 0;
436 }
437
438 /* Simplified localtime to provide timevalues for ffdc.
439 * Taken from libc/stdtime/localtime.c
440 */
441 void 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
481 static 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
505 int ips_ffdc_reset(ips_softc_t *sc)
506 {
507 ips_cmd_status_t *status;
508 status = malloc(sizeof(ips_cmd_status_t), M_IPSBUF, 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_IPSBUF);
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_IPSBUF);
520 return 0;
521 }
522
523 static 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
549 static 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
576 static 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
618 exit:
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
626 int ips_update_nvram(ips_softc_t *sc)
627 {
628 ips_cmd_status_t *status;
629 status = malloc(sizeof(ips_cmd_status_t), M_IPSBUF, 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_IPSBUF);
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_IPSBUF);
641 return 0;
642
643
644 }
645
646
647 static 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
668 static 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
690 int ips_clear_adapter(ips_softc_t *sc)
691 {
692 ips_cmd_status_t *status;
693 status = malloc(sizeof(ips_cmd_status_t), M_IPSBUF, 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_IPSBUF);
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_IPSBUF);
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_IPSBUF);
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_IPSBUF);
719 return 1;
720 }
721
722 free(status, M_IPSBUF);
723 return 0;
724 }
Cache object: 15475e5b69522d4cd601c8ba0d411161
|