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