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