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.2/sys/dev/ips/ips_commands.c 124170 2004-01-06 15:52:23Z 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 */
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 = 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
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 }
Cache object: 95c1157073eb618d475b0e43ccda9aba
|