diff options
| author | Scott Long <scottl@FreeBSD.org> | 2005-01-30 17:45:45 +0000 |
|---|---|---|
| committer | Scott Long <scottl@FreeBSD.org> | 2005-01-30 17:45:45 +0000 |
| commit | 7765040ebc0bf6d7c9a27cdd4da04636f4cbb2eb (patch) | |
| tree | 67a0aca7070b8cf1ffec290dc888e322dece9641 /sys/dev/ips/ips_disk.c | |
| parent | 7449260bfd1ab413abe4d9087d0097b4417967df (diff) | |
Notes
Diffstat (limited to 'sys/dev/ips/ips_disk.c')
| -rw-r--r-- | sys/dev/ips/ips_disk.c | 134 |
1 files changed, 133 insertions, 1 deletions
diff --git a/sys/dev/ips/ips_disk.c b/sys/dev/ips/ips_disk.c index 4ddcfa19a457..7a8f5fd85ac8 100644 --- a/sys/dev/ips/ips_disk.c +++ b/sys/dev/ips/ips_disk.c @@ -36,6 +36,12 @@ static int ipsd_probe(device_t dev); static int ipsd_attach(device_t dev); static int ipsd_detach(device_t dev); +static int ipsd_dump(void *arg, void *virtual, vm_offset_t physical, + off_t offset, size_t length); +static void ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, + int error); +static void ipsd_dump_block_complete(ips_command_t *command); + static disk_open_t ipsd_open; static disk_close_t ipsd_close; static disk_strategy_t ipsd_strategy; @@ -47,7 +53,6 @@ static device_method_t ipsd_methods[] = { { 0, 0 } }; - static driver_t ipsd_driver = { "ipsd", ipsd_methods, @@ -136,6 +141,7 @@ static int ipsd_attach(device_t dev) dsc->ipsd_disk->d_open = ipsd_open; dsc->ipsd_disk->d_close = ipsd_close; dsc->ipsd_disk->d_strategy = ipsd_strategy; + dsc->ipsd_disk->d_dump = ipsd_dump; totalsectors = dsc->sc->drives[dsc->disk_number].sector_count; if ((totalsectors > 0x400000) && @@ -168,3 +174,129 @@ static int ipsd_detach(device_t dev) disk_destroy(dsc->ipsd_disk); return 0; } + +static int +ipsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, + size_t length) +{ + ipsdisk_softc_t *dsc; + ips_softc_t *sc; + ips_command_t *command; + ips_io_cmd *command_struct; + struct disk *dp; + void *va; + off_t off; + size_t len; + int error = 0; + + dp = arg; + dsc = dp->d_drv1; + sc = dsc->sc; + + if (dsc == NULL) + return (EINVAL); + + if (ips_get_free_cmd(sc, &command, 0) != 0) { + printf("ipsd: failed to get cmd for dump\n"); + return (ENOMEM); + } + + command->data_dmatag = sc->sg_dmatag; + command->callback = ipsd_dump_block_complete; + + command_struct = (ips_io_cmd *)command->command_buffer; + command_struct->id = command->id; + command_struct->drivenum= sc->drives[dsc->disk_number].drivenum; + + off = offset; + va = virtual; + + while (length > 0) { + len = + (length > IPS_MAX_IO_SIZE) ? IPS_MAX_IO_SIZE : length; + + command_struct->lba = off / IPS_BLKSIZE; + + if (bus_dmamap_load(command->data_dmatag, command->data_dmamap, + va, len, ipsd_dump_map_sg, command, BUS_DMA_NOWAIT) != 0) { + error = EIO; + break; + } + if (COMMAND_ERROR(&command->status)) { + error = EIO; + break; + } + + length -= len; + off += len; + va = (uint8_t *)va + len; + } + + ips_insert_free_cmd(command->sc, command); + return (error); +} + +static void +ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + ips_softc_t *sc; + ips_command_t *command; + ips_sg_element_t *sg_list; + ips_io_cmd *command_struct; + int i, length; + + command = (ips_command_t *)arg; + sc = command->sc; + length = 0; + + if (error) { + printf("ipsd_dump_map_sg: error %d\n", error); + command->status.value = IPS_ERROR_STATUS; + return; + } + + command_struct = (ips_io_cmd *)command->command_buffer; + + if (nsegs != 1) { + command_struct->segnum = nsegs; + sg_list = (ips_sg_element_t *)((uint8_t *) + command->command_buffer + IPS_COMMAND_LEN); + for (i = 0; i < nsegs; i++) { + sg_list[i].addr = segs[i].ds_addr; + sg_list[i].len = segs[i].ds_len; + length += segs[i].ds_len; + } + command_struct->buffaddr = + (uint32_t)command->command_phys_addr + IPS_COMMAND_LEN; + command_struct->command = IPS_SG_WRITE_CMD; + } else { + command_struct->buffaddr = segs[0].ds_addr; + length = segs[0].ds_len; + command_struct->segnum = 0; + command_struct->command = IPS_WRITE_CMD; + } + + length = (length + IPS_BLKSIZE - 1) / IPS_BLKSIZE; + command_struct->length = length; + bus_dmamap_sync(sc->command_dmatag, command->command_dmamap, + BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(command->data_dmatag, command->data_dmamap, + BUS_DMASYNC_PREWRITE); + + sc->ips_issue_cmd(command); + sc->ips_poll_cmd(command); + return; +} + +static void +ipsd_dump_block_complete(ips_command_t *command) +{ + + if (COMMAND_ERROR(&command->status)) + printf("ipsd_dump completion error= 0x%x\n", + command->status.value); + + bus_dmamap_sync(command->data_dmatag, command->data_dmamap, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(command->data_dmatag, command->data_dmamap); +} |
