diff options
Diffstat (limited to 'sys/cam/ctl/ctl_util.c')
-rw-r--r-- | sys/cam/ctl/ctl_util.c | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/sys/cam/ctl/ctl_util.c b/sys/cam/ctl/ctl_util.c new file mode 100644 index 0000000..3ca0aa2 --- /dev/null +++ b/sys/cam/ctl/ctl_util.c @@ -0,0 +1,843 @@ +/*- + * Copyright (c) 2003 Silicon Graphics International Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + * + * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_util.c#2 $ + */ +/* + * CAM Target Layer SCSI library + * + * Author: Ken Merry <ken@FreeBSD.org> + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef _KERNEL +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/types.h> +#include <sys/malloc.h> +#else /* __KERNEL__ */ +#include <sys/types.h> +#include <sys/time.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#endif /* __KERNEL__ */ +#include <sys/sbuf.h> +#include <sys/queue.h> +#include <sys/callout.h> +#include <cam/scsi/scsi_all.h> +#include <cam/ctl/ctl_io.h> +#include <cam/ctl/ctl_scsi_all.h> +#include <cam/ctl/ctl_util.h> + +struct ctl_status_desc { + ctl_io_status status; + const char *description; +}; + +struct ctl_task_desc { + ctl_task_type task_action; + const char *description; +}; +static struct ctl_status_desc ctl_status_table[] = { + {CTL_STATUS_NONE, "No Status"}, + {CTL_SUCCESS, "Command Completed Successfully"}, + {CTL_CMD_TIMEOUT, "Command Timed Out"}, + {CTL_SEL_TIMEOUT, "Selection Timeout"}, + {CTL_ERROR, "Command Failed"}, + {CTL_SCSI_ERROR, "SCSI Error"}, + {CTL_CMD_ABORTED, "Command Aborted"}, +}; + +static struct ctl_task_desc ctl_task_table[] = { + {CTL_TASK_ABORT_TASK, "Abort Task"}, + {CTL_TASK_ABORT_TASK_SET, "Abort Task Set"}, + {CTL_TASK_CLEAR_ACA, "Clear ACA"}, + {CTL_TASK_CLEAR_TASK_SET, "Clear Task Set"}, + {CTL_TASK_LUN_RESET, "LUN Reset"}, + {CTL_TASK_TARGET_RESET, "Target Reset"}, + {CTL_TASK_BUS_RESET, "Bus Reset"}, + {CTL_TASK_PORT_LOGIN, "Port Login"}, + {CTL_TASK_PORT_LOGOUT, "Port Logout"} +}; + +void +ctl_scsi_tur(union ctl_io *io, ctl_tag_type tag_type, uint8_t control) +{ + struct ctl_scsiio *ctsio; + struct scsi_test_unit_ready *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + cdb = (struct scsi_test_unit_ready *)ctsio->cdb; + + cdb->opcode = TEST_UNIT_READY; + cdb->control = control; + io->io_hdr.flags = CTL_FLAG_DATA_NONE; + ctsio->tag_type = tag_type; + ctsio->cdb_len = sizeof(*cdb); + ctsio->ext_data_len = 0; + ctsio->ext_data_ptr = NULL; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_inquiry(union ctl_io *io, uint8_t *data_ptr, int32_t data_len, + uint8_t byte2, uint8_t page_code, ctl_tag_type tag_type, + uint8_t control) +{ + struct ctl_scsiio *ctsio; + struct scsi_inquiry *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + cdb = (struct scsi_inquiry *)ctsio->cdb; + + cdb->opcode = INQUIRY; + cdb->byte2 = byte2; + cdb->page_code = page_code; + cdb->control = control; + scsi_ulto2b(data_len, cdb->length); + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + ctsio->tag_type = tag_type; + ctsio->cdb_len = sizeof(*cdb); + ctsio->ext_data_len = data_len; + ctsio->ext_data_ptr = data_ptr; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_request_sense(union ctl_io *io, uint8_t *data_ptr, + int32_t data_len, uint8_t byte2, ctl_tag_type tag_type, + uint8_t control) +{ + struct ctl_scsiio *ctsio; + struct scsi_request_sense *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + cdb = (struct scsi_request_sense *)ctsio->cdb; + + cdb->opcode = REQUEST_SENSE; + cdb->byte2 = byte2; + cdb->control = control; + cdb->length = data_len; + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + ctsio->tag_type = tag_type; + ctsio->cdb_len = sizeof(*cdb); + ctsio->ext_data_ptr = data_ptr; + ctsio->ext_data_len = data_len; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_report_luns(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, + uint8_t select_report, ctl_tag_type tag_type, + uint8_t control) +{ + struct ctl_scsiio *ctsio; + struct scsi_report_luns *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + cdb = (struct scsi_report_luns *)ctsio->cdb; + + cdb->opcode = REPORT_LUNS; + cdb->select_report = select_report; + scsi_ulto4b(data_len, cdb->length); + cdb->control = control; + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + ctsio->tag_type = tag_type; + ctsio->cdb_len = sizeof(*cdb); + ctsio->ext_data_ptr = data_ptr; + ctsio->ext_data_len = data_len; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_read_write_buffer(union ctl_io *io, uint8_t *data_ptr, + uint32_t data_len, int read_buffer, uint8_t mode, + uint8_t buffer_id, uint32_t buffer_offset, + ctl_tag_type tag_type, uint8_t control) +{ + struct ctl_scsiio *ctsio; + struct scsi_write_buffer *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + cdb = (struct scsi_write_buffer *)ctsio->cdb; + + if (read_buffer != 0) + cdb->opcode = READ_BUFFER; + else + cdb->opcode = WRITE_BUFFER; + + cdb->byte2 = mode & RWB_MODE; + cdb->buffer_id = buffer_id; + scsi_ulto3b(buffer_offset, cdb->offset); + scsi_ulto3b(data_len, cdb->length); + cdb->control = control; + io->io_hdr.io_type = CTL_IO_SCSI; + if (read_buffer != 0) + io->io_hdr.flags = CTL_FLAG_DATA_IN; + else + io->io_hdr.flags = CTL_FLAG_DATA_OUT; + ctsio->tag_type = tag_type; + ctsio->cdb_len = sizeof(*cdb); + ctsio->ext_data_ptr = data_ptr; + ctsio->ext_data_len = data_len; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_read_write(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, + int read_op, uint8_t byte2, int minimum_cdb_size, + uint64_t lba, uint32_t num_blocks, ctl_tag_type tag_type, + uint8_t control) +{ + struct ctl_scsiio *ctsio; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + ctsio = &io->scsiio; + + /* + * Pick out the smallest CDB that will hold the user's request. + * minimum_cdb_size allows cranking the CDB size up, even for + * requests that would not normally need a large CDB. This can be + * useful for testing (e.g. to make sure READ_16 support works without + * having an array larger than 2TB) and for compatibility -- e.g. + * if your device doesn't support READ_6. (ATAPI drives don't.) + */ + if ((minimum_cdb_size < 10) + && ((lba & 0x1fffff) == lba) + && ((num_blocks & 0xff) == num_blocks) + && (byte2 == 0)) { + struct scsi_rw_6 *cdb; + + /* + * Note that according to SBC-2, the target should return 256 + * blocks if the transfer length in a READ(6) or WRITE(6) CDB + * is set to 0. Since it's possible that some targets + * won't do the right thing, we only send a READ(6) or + * WRITE(6) for transfer sizes up to and including 255 blocks. + */ + cdb = (struct scsi_rw_6 *)ctsio->cdb; + + cdb->opcode = (read_op) ? READ_6 : WRITE_6; + scsi_ulto3b(lba, cdb->addr); + cdb->length = num_blocks & 0xff; + cdb->control = control; + + ctsio->cdb_len = sizeof(*cdb); + + } else if ((minimum_cdb_size < 12) + && ((num_blocks & 0xffff) == num_blocks) + && ((lba & 0xffffffff) == lba)) { + struct scsi_rw_10 *cdb; + + cdb = (struct scsi_rw_10 *)ctsio->cdb; + + cdb->opcode = (read_op) ? READ_10 : WRITE_10; + cdb->byte2 = byte2; + scsi_ulto4b(lba, cdb->addr); + cdb->reserved = 0; + scsi_ulto2b(num_blocks, cdb->length); + cdb->control = control; + + ctsio->cdb_len = sizeof(*cdb); + } else if ((minimum_cdb_size < 16) + && ((num_blocks & 0xffffffff) == num_blocks) + && ((lba & 0xffffffff) == lba)) { + struct scsi_rw_12 *cdb; + + cdb = (struct scsi_rw_12 *)ctsio->cdb; + + cdb->opcode = (read_op) ? READ_12 : WRITE_12; + cdb->byte2 = byte2; + scsi_ulto4b(lba, cdb->addr); + scsi_ulto4b(num_blocks, cdb->length); + cdb->reserved = 0; + cdb->control = control; + + ctsio->cdb_len = sizeof(*cdb); + } else { + struct scsi_rw_16 *cdb; + + cdb = (struct scsi_rw_16 *)ctsio->cdb; + + cdb->opcode = (read_op) ? READ_16 : WRITE_16; + cdb->byte2 = byte2; + scsi_u64to8b(lba, cdb->addr); + scsi_ulto4b(num_blocks, cdb->length); + cdb->reserved = 0; + cdb->control = control; + + ctsio->cdb_len = sizeof(*cdb); + } + + io->io_hdr.io_type = CTL_IO_SCSI; + if (read_op != 0) + io->io_hdr.flags = CTL_FLAG_DATA_IN; + else + io->io_hdr.flags = CTL_FLAG_DATA_OUT; + ctsio->tag_type = tag_type; + ctsio->ext_data_ptr = data_ptr; + ctsio->ext_data_len = data_len; + ctsio->ext_sg_entries = 0; + ctsio->ext_data_filled = 0; + ctsio->sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_read_capacity(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, + uint32_t addr, int reladr, int pmi, + ctl_tag_type tag_type, uint8_t control) +{ + struct scsi_read_capacity *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + cdb = (struct scsi_read_capacity *)io->scsiio.cdb; + + cdb->opcode = READ_CAPACITY; + if (reladr) + cdb->byte2 = SRC_RELADR; + if (pmi) + cdb->pmi = SRC_PMI; + scsi_ulto4b(addr, cdb->addr); + cdb->control = control; + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_read_capacity_16(union ctl_io *io, uint8_t *data_ptr, + uint32_t data_len, uint64_t addr, int reladr, + int pmi, ctl_tag_type tag_type, uint8_t control) +{ + struct scsi_read_capacity_16 *cdb; + + ctl_scsi_zero_io(io); + + io->io_hdr.io_type = CTL_IO_SCSI; + cdb = (struct scsi_read_capacity_16 *)io->scsiio.cdb; + + cdb->opcode = SERVICE_ACTION_IN; + cdb->service_action = SRC16_SERVICE_ACTION; + if (reladr) + cdb->reladr |= SRC16_RELADR; + if (pmi) + cdb->reladr |= SRC16_PMI; + scsi_u64to8b(addr, cdb->addr); + scsi_ulto4b(data_len, cdb->alloc_len); + cdb->control = control; + + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_mode_sense(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, + int dbd, int llbaa, uint8_t page_code, uint8_t pc, + uint8_t subpage, int minimum_cdb_size, + ctl_tag_type tag_type, uint8_t control) +{ + ctl_scsi_zero_io(io); + + if ((minimum_cdb_size < 10) + && (llbaa == 0) + && (data_len < 256)) { + struct scsi_mode_sense_6 *cdb; + + cdb = (struct scsi_mode_sense_6 *)io->scsiio.cdb; + + cdb->opcode = MODE_SENSE_6; + if (dbd) + cdb->byte2 |= SMS_DBD; + cdb->page = page_code | pc; + cdb->subpage = subpage; + cdb->length = data_len; + cdb->control = control; + } else { + struct scsi_mode_sense_10 *cdb; + + cdb = (struct scsi_mode_sense_10 *)io->scsiio.cdb; + + cdb->opcode = MODE_SENSE_10; + if (dbd) + cdb->byte2 |= SMS_DBD; + if (llbaa) + cdb->byte2 |= SMS10_LLBAA; + cdb->page = page_code | pc; + cdb->subpage = subpage; + scsi_ulto2b(data_len, cdb->length); + cdb->control = control; + } + + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_start_stop(union ctl_io *io, int start, int load_eject, int immediate, + int power_conditions, int onoffline __unused, + ctl_tag_type tag_type, uint8_t control) +{ + struct scsi_start_stop_unit *cdb; + + cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; + + ctl_scsi_zero_io(io); + + cdb->opcode = START_STOP_UNIT; + if (immediate) + cdb->byte2 |= SSS_IMMED; +#ifdef NEEDTOPORT + if (onoffline) + cdb->byte2 |= SSS_ONOFFLINE; +#endif + cdb->how = power_conditions; + if (load_eject) + cdb->how |= SSS_LOEJ; + if (start) + cdb->how |= SSS_START; + cdb->control = control; + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_NONE; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = NULL; + io->scsiio.ext_data_len = 0; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_sync_cache(union ctl_io *io, int immed, int reladr, + int minimum_cdb_size, uint64_t starting_lba, + uint32_t block_count, ctl_tag_type tag_type, + uint8_t control) +{ + ctl_scsi_zero_io(io); + + if ((minimum_cdb_size < 16) + && ((block_count & 0xffff) == block_count) + && ((starting_lba & 0xffffffff) == starting_lba)) { + struct scsi_sync_cache *cdb; + + cdb = (struct scsi_sync_cache *)io->scsiio.cdb; + + cdb->opcode = SYNCHRONIZE_CACHE; + if (reladr) + cdb->byte2 |= SSC_RELADR; + + if (immed) + cdb->byte2 |= SSC_IMMED; + + scsi_ulto4b(starting_lba, cdb->begin_lba); + scsi_ulto2b(block_count, cdb->lb_count); + cdb->control = control; + } else { + struct scsi_sync_cache_16 *cdb; + + cdb = (struct scsi_sync_cache_16 *)io->scsiio.cdb; + + cdb->opcode = SYNCHRONIZE_CACHE_16; + if (reladr) + cdb->byte2 |= SSC_RELADR; + + if (immed) + cdb->byte2 |= SSC_IMMED; + + scsi_u64to8b(starting_lba, cdb->begin_lba); + scsi_ulto4b(block_count, cdb->lb_count); + cdb->control = control; + } + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_NONE; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = NULL; + io->scsiio.ext_data_len = 0; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_persistent_res_in(union ctl_io *io, uint8_t *data_ptr, + uint32_t data_len, int action, + ctl_tag_type tag_type, uint8_t control) +{ + + struct scsi_per_res_in *cdb; + + ctl_scsi_zero_io(io); + + cdb = (struct scsi_per_res_in *)io->scsiio.cdb; + cdb->opcode = PERSISTENT_RES_IN; + cdb->action = action; + scsi_ulto2b(data_len, cdb->length); + cdb->control = control; + + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +void +ctl_scsi_persistent_res_out(union ctl_io *io, uint8_t *data_ptr, + uint32_t data_len, int action, int type, + uint64_t key, uint64_t sa_key, + ctl_tag_type tag_type, uint8_t control) +{ + + struct scsi_per_res_out *cdb; + struct scsi_per_res_out_parms *params; + + ctl_scsi_zero_io(io); + + cdb = (struct scsi_per_res_out *)io->scsiio.cdb; + params = (struct scsi_per_res_out_parms *)data_ptr; + + cdb->opcode = PERSISTENT_RES_OUT; + if (action == 5) + cdb->action = 6; + else + cdb->action = action; + switch(type) + { + case 0: + cdb->scope_type = 1; + break; + case 1: + cdb->scope_type = 3; + break; + case 2: + cdb->scope_type = 5; + break; + case 3: + cdb->scope_type = 6; + break; + case 4: + cdb->scope_type = 7; + break; + case 5: + cdb->scope_type = 8; + break; + } + scsi_ulto4b(data_len, cdb->length); + cdb->control = control; + + scsi_u64to8b(key, params->res_key.key); + scsi_u64to8b(sa_key, params->serv_act_res_key); + + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_OUT; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; + +} + +void +ctl_scsi_maintenance_in(union ctl_io *io, uint8_t *data_ptr, uint32_t data_len, + uint8_t action, ctl_tag_type tag_type, uint8_t control) +{ + struct scsi_maintenance_in *cdb; + + ctl_scsi_zero_io(io); + + cdb = (struct scsi_maintenance_in *)io->scsiio.cdb; + cdb->opcode = MAINTENANCE_IN; + cdb->byte2 = action; + scsi_ulto4b(data_len, cdb->length); + cdb->control = control; + + io->io_hdr.io_type = CTL_IO_SCSI; + io->io_hdr.flags = CTL_FLAG_DATA_IN; + io->scsiio.tag_type = tag_type; + io->scsiio.ext_data_ptr = data_ptr; + io->scsiio.ext_data_len = data_len; + io->scsiio.ext_sg_entries = 0; + io->scsiio.ext_data_filled = 0; + io->scsiio.sense_len = SSD_FULL_SIZE; +} + +#ifndef _KERNEL +union ctl_io * +ctl_scsi_alloc_io(struct ctl_id initid) +{ + union ctl_io *io; + + io = (union ctl_io *)malloc(sizeof(*io)); + if (io == NULL) + goto bailout; + + io->io_hdr.nexus.initid = initid; + +bailout: + return (io); +} + +void +ctl_scsi_free_io(union ctl_io *io) +{ + free(io); +} + +#endif /* !_KERNEL */ +void +ctl_scsi_zero_io(union ctl_io *io) +{ + void *pool_ref; + + if (io == NULL) + return; + + pool_ref = io->io_hdr.pool; + + memset(io, 0, sizeof(*io)); + + io->io_hdr.pool = pool_ref; +} + +const char * +ctl_scsi_task_string(struct ctl_taskio *taskio) +{ + unsigned int i; + + for (i = 0; i < (sizeof(ctl_task_table)/sizeof(ctl_task_table[0])); + i++) { + if (taskio->task_action == ctl_task_table[i].task_action) { + return (ctl_task_table[i].description); + } + } + + return (NULL); +} + +void +ctl_io_error_sbuf(union ctl_io *io, struct scsi_inquiry_data *inq_data, + struct sbuf *sb) +{ + struct ctl_status_desc *status_desc; + char path_str[64]; + unsigned int i; + + status_desc = NULL; + + for (i = 0; i < (sizeof(ctl_status_table)/sizeof(ctl_status_table[0])); + i++) { + if ((io->io_hdr.status & CTL_STATUS_MASK) == + ctl_status_table[i].status) { + status_desc = &ctl_status_table[i]; + break; + } + } + + ctl_scsi_path_string(io, path_str, sizeof(path_str)); + + switch (io->io_hdr.io_type) { + case CTL_IO_SCSI: + sbuf_cat(sb, path_str); + + ctl_scsi_command_string(&io->scsiio, NULL, sb); + + sbuf_printf(sb, "\n"); + + sbuf_printf(sb, "%sTag: 0x%04x, Type: %d\n", path_str, + io->scsiio.tag_num, io->scsiio.tag_type); + break; + case CTL_IO_TASK: { + const char *task_desc; + + sbuf_cat(sb, path_str); + + task_desc = ctl_scsi_task_string(&io->taskio); + + if (task_desc == NULL) + sbuf_printf(sb, "Unknown Task Action %d (%#x)", + io->taskio.task_action, + io->taskio.task_action); + else + sbuf_printf(sb, "Task Action: %s", task_desc); + + sbuf_printf(sb, "\n"); + + switch (io->taskio.task_action) { + case CTL_TASK_ABORT_TASK: + case CTL_TASK_ABORT_TASK_SET: + case CTL_TASK_CLEAR_TASK_SET: + sbuf_printf(sb, "%sTag: 0x%04x, Type: %d\n", path_str, + io->taskio.tag_num, + io->taskio.tag_type); + break; + default: + break; + } + break; + } + default: + break; + } + + sbuf_cat(sb, path_str); + if (status_desc == NULL) + sbuf_printf(sb, "CTL Status: Unknown status %#x\n", + io->io_hdr.status); + else + sbuf_printf(sb, "CTL Status: %s\n", status_desc->description); + + if ((io->io_hdr.io_type == CTL_IO_SCSI) + && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_SCSI_ERROR)) { + sbuf_cat(sb, path_str); + sbuf_printf(sb, "SCSI Status: %s\n", + ctl_scsi_status_string(&io->scsiio)); + + if (io->scsiio.scsi_status == SCSI_STATUS_CHECK_COND) + ctl_scsi_sense_sbuf(&io->scsiio, inq_data, + sb, SSS_FLAG_NONE); + } +} + +char * +ctl_io_error_string(union ctl_io *io, struct scsi_inquiry_data *inq_data, + char *str, int str_len) +{ + struct sbuf sb; + + sbuf_new(&sb, str, str_len, SBUF_FIXEDLEN); + + ctl_io_error_sbuf(io, inq_data, &sb); + + sbuf_finish(&sb); + + return (sbuf_data(&sb)); +} + +#ifdef _KERNEL + +void +ctl_io_error_print(union ctl_io *io, struct scsi_inquiry_data *inq_data) +{ + char str[512]; +#ifdef NEEDTOPORT + char *message; + char *line; + + message = io_error_string(io, inq_data, str, sizeof(str)); + + for (line = strsep(&message, "\n"); line != NULL; + line = strsep(&message, "\n")) { + csevent_log(CSC_CTL | CSC_SHELF_SW | CTL_ERROR_REPORT, + csevent_LogType_Trace, + csevent_Severity_Information, + csevent_AlertLevel_Green, + csevent_FRU_Firmware, + csevent_FRU_Unknown, "%s", line); + } +#else + printf("%s", ctl_io_error_string(io, inq_data, str, sizeof(str))); +#endif + +} + +#else /* _KERNEL */ + +void +ctl_io_error_print(union ctl_io *io, struct scsi_inquiry_data *inq_data, + FILE *ofile) +{ + char str[512]; + + fprintf(ofile, "%s", ctl_io_error_string(io, inq_data, str, + sizeof(str))); +} + +#endif /* _KERNEL */ + +/* + * vim: ts=8 + */ |