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