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