diff options
Diffstat (limited to 'sys/cam/scsi/scsi_all.c')
-rw-r--r-- | sys/cam/scsi/scsi_all.c | 143 |
1 files changed, 138 insertions, 5 deletions
diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 129847f..4f892bd 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: scsi_all.c,v 1.1 1998/09/15 06:36:33 gibbs Exp $ */ #include <sys/param.h> @@ -2627,6 +2627,135 @@ scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t retries, scsi_ulto2b(lb_count, scsi_cmd->lb_count); } +void +scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int readop, u_int8_t byte2, + int minimum_cmd_size, u_int32_t lba, u_int32_t block_count, + u_int8_t *data_ptr, u_int32_t dxfer_len, u_int8_t sense_len, + u_int32_t timeout) +{ + u_int8_t cdb_len; + /* + * Use the smallest possible command to perform the operation + * as some legacy hardware does not support the 10 byte + * commands. If any of the lower 5 bits in byte2 is set, we have + * to go with a larger command. + * + */ + if ((minimum_cmd_size < 10) + && ((lba & 0x1fffff) == lba) + && ((block_count & 0xff) == block_count) + && ((byte2 & 0xe0) == 0)) { + /* + * We can fit in a 6 byte cdb. + */ + struct scsi_rw_6 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_6 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_6 : WRITE_6; + scsi_ulto3b(lba, scsi_cmd->addr); + scsi_cmd->length = block_count & 0xff; + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("6byte: %x%x%x:%d:%d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->length, dxfer_len)); + } else if ((minimum_cmd_size < 12) + && ((block_count & 0xffff) == block_count)) { + /* + * Need a 10 byte cdb. + */ + struct scsi_rw_10 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_10 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_10 : WRITE_10; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto2b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("10byte: %x%x%x%x:%x%x: %d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->addr[3], scsi_cmd->length[0], + scsi_cmd->length[1], dxfer_len)); + } else { + /* + * The block count is too big for a 10 byte CDB, use a 12 + * byte CDB. READ/WRITE(12) are currently only defined for + * optical devices. + */ + struct scsi_rw_12 *scsi_cmd; + + scsi_cmd = (struct scsi_rw_12 *)&csio->cdb_io.cdb_bytes; + scsi_cmd->opcode = readop ? READ_12 : WRITE_12; + scsi_cmd->byte2 = byte2; + scsi_ulto4b(lba, scsi_cmd->addr); + scsi_cmd->reserved = 0; + scsi_ulto4b(block_count, scsi_cmd->length); + scsi_cmd->control = 0; + cdb_len = sizeof(*scsi_cmd); + + CAM_DEBUG(csio->ccb_h.path, CAM_DEBUG_SUBTRACE, + ("12byte: %x%x%x%x:%x%x%x%x: %d\n", scsi_cmd->addr[0], + scsi_cmd->addr[1], scsi_cmd->addr[2], + scsi_cmd->addr[3], scsi_cmd->length[0], + scsi_cmd->length[1], scsi_cmd->length[2], + scsi_cmd->length[3], dxfer_len)); + } + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/readop ? CAM_DIR_IN : CAM_DIR_OUT, + tag_action, + data_ptr, + dxfer_len, + sense_len, + cdb_len, + timeout); +} + +void +scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + u_int8_t tag_action, int start, int load_eject, + int immediate, u_int8_t sense_len, u_int32_t timeout) +{ + struct scsi_start_stop_unit *scsi_cmd; + int extra_flags = 0; + + scsi_cmd = (struct scsi_start_stop_unit *)&csio->cdb_io.cdb_bytes; + bzero(scsi_cmd, sizeof(*scsi_cmd)); + scsi_cmd->opcode = START_STOP_UNIT; + if (start != 0) { + scsi_cmd->how |= SSS_START; + /* it takes a lot of power to start a drive */ + extra_flags |= CAM_HIGH_POWER; + } + if (load_eject != 0) + scsi_cmd->how |= SSS_LOEJ; + if (immediate != 0) + scsi_cmd->byte2 |= SSS_IMMED; + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_NONE | extra_flags, + tag_action, + /*data_ptr*/NULL, + /*dxfer_len*/0, + sense_len, + sizeof(*scsi_cmd), + timeout); + +} + + /* * Try make as good a match as possible with * available sub drivers @@ -2645,8 +2774,10 @@ scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE : entry->media_type & SIP_MEDIA_FIXED) && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) - && (cam_strmatch(inq->product, entry->product, sizeof(inq->product)) == 0) - && (cam_strmatch(inq->revision, entry->revision, sizeof(inq->revision)) == 0)) { + && (cam_strmatch(inq->product, entry->product, + sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, + sizeof(inq->revision)) == 0)) { return (0); } return (-1); @@ -2670,8 +2801,10 @@ scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE : entry->media_type & SIP_MEDIA_FIXED) && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) - && (cam_strmatch(inq->product, entry->product, sizeof(inq->product)) == 0) - && (cam_strmatch(inq->revision, entry->revision, sizeof(inq->revision)) == 0)) { + && (cam_strmatch(inq->product, entry->product, + sizeof(inq->product)) == 0) + && (cam_strmatch(inq->revision, entry->revision, + sizeof(inq->revision)) == 0)) { return (0); } return (-1); |