diff options
Diffstat (limited to 'scsi/scsi_disk.c')
-rw-r--r-- | scsi/scsi_disk.c | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/scsi/scsi_disk.c b/scsi/scsi_disk.c new file mode 100644 index 0000000..99bbe76 --- /dev/null +++ b/scsi/scsi_disk.c @@ -0,0 +1,624 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * File: scsi_disk.c + * Author: Alessandro Forin, Carnegie Mellon University + * Date: 10/90 + * + * Middle layer of the SCSI driver: SCSI protocol implementation + * + * This file contains code for SCSI commands for DISK devices. + */ + +#include <string.h> + +#include <mach/std_types.h> +#include <scsi/compat_30.h> + +#include <scsi/scsi.h> +#include <scsi/scsi2.h> +#include <scsi/scsi_defs.h> + +#if (NSCSI > 0) + + +char *scdisk_name(internal) + boolean_t internal; +{ + return internal ? "rz" : "disk"; +} + +/* + * SCSI commands partially specific to disks + */ +void scdisk_read( tgt, secno, ior) + register target_info_t *tgt; + register unsigned int secno; + io_req_t ior; +{ + scsi_cmd_read_t *cmd; + register unsigned len; + unsigned int max_dma_data; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + if (len < tgt->block_size) + len = tgt->block_size; + + cmd = (scsi_cmd_read_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_READ; + cmd->scsi_cmd_lun_and_lba1 = (secno>>16)&SCSI_LBA_MASK; + cmd->scsi_cmd_lba2 = (secno>> 8)&0xff; + cmd->scsi_cmd_lba3 = (secno )&0xff; + cmd->scsi_cmd_xfer_len = len / tgt->block_size; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_READ; + + scsi_go(tgt, sizeof(*cmd), len, FALSE); +} + +void scdisk_write( tgt, secno, ior) + register target_info_t *tgt; + register unsigned int secno; + io_req_t ior; +{ + scsi_cmd_write_t *cmd; + unsigned len; /* in bytes */ + unsigned int max_dma_data; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + if (len < tgt->block_size) + len = tgt->block_size; + + cmd = (scsi_cmd_write_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_WRITE; + cmd->scsi_cmd_lun_and_lba1 = (secno>>16)&SCSI_LBA_MASK; + cmd->scsi_cmd_lba2 = (secno>> 8)&0xff; + cmd->scsi_cmd_lba3 = (secno )&0xff; + cmd->scsi_cmd_xfer_len = len / tgt->block_size; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_WRITE; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + + +int scdisk_mode_select(tgt, lbn, ior, mdata, mlen, save) + register target_info_t *tgt; + register int lbn; + io_req_t ior; + char *mdata; + int mlen, save; +{ + scsi_cmd_mode_select_t *cmd; + scsi_mode_select_param_t *parm; + + bzero(tgt->cmd_ptr, sizeof(*cmd) + sizeof(*parm)); + cmd = (scsi_cmd_mode_select_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_MODE_SELECT; + cmd->scsi_cmd_lun_and_lba1 = SCSI_CMD_MSL_PF; /* XXX only if... */ + cmd->scsi_cmd_xfer_len = sizeof(scsi_mode_select_param_t);/* no vuq */ + + parm = (scsi_mode_select_param_t*) (cmd + 1); + if (mdata) { + cmd->scsi_cmd_xfer_len = mlen; + bcopy(mdata, (char*)parm, mlen); + if (save) + cmd->scsi_cmd_lun_and_lba1 |= SCSI_CMD_MSL_SP; + } else { + /* parm->medium_type = if (floppy)disk.. */ + parm->desc_len = 8; + /* this really is the LBN */ + parm->descs[0].density_code = 0;/* XXX default XXX */ + parm->descs[0].reclen1 = (lbn>>16)&0xff; + parm->descs[0].reclen2 = (lbn>> 8)&0xff; + parm->descs[0].reclen3 = (lbn )&0xff; + mlen = sizeof(*parm); + } + + tgt->cur_cmd = SCSI_CMD_MODE_SELECT; + + scsi_go_and_wait(tgt, sizeof(*cmd) + mlen, 0, ior); + + return tgt->done; +} + +/* + * SCSI commands fully specific to disks + */ +int scsi_read_capacity( tgt, lbn, ior) + register target_info_t *tgt; + int lbn; + io_req_t ior; +{ + scsi_cmd_read_capacity_t *cmd; + + bzero(tgt->cmd_ptr, sizeof(*cmd)); + cmd = (scsi_cmd_read_capacity_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_READ_CAPACITY; + /* all zeroes, unless... */ + if (lbn) { + cmd->scsi_cmd_rcap_flags = SCSI_CMD_RCAP_PMI; + cmd->scsi_cmd_lba1 = (lbn>>24); + cmd->scsi_cmd_lba2 = (lbn>>16)&0xff; + cmd->scsi_cmd_lba3 = (lbn>> 8)&0xff; + cmd->scsi_cmd_lba4 = (lbn )&0xff; + } + + tgt->cur_cmd = SCSI_CMD_READ_CAPACITY; + + scsi_go_and_wait(tgt, sizeof(*cmd), sizeof(scsi_rcap_data_t),ior); + + return tgt->done; +} + +void scsi_reassign_blocks( tgt, defect_list, n_defects, ior) + register target_info_t *tgt; + unsigned int *defect_list; /* In ascending order ! */ + int n_defects; + io_req_t ior; +{ + scsi_cmd_reassign_blocks_t *cmd; + scsi_Ldefect_data_t *parm; + + cmd = (scsi_cmd_reassign_blocks_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_REASSIGN_BLOCKS; + cmd->scsi_cmd_lun_and_lba1 = 0; + cmd->scsi_cmd_lba2 = 0; + cmd->scsi_cmd_lba3 = 0; + cmd->scsi_cmd_xfer_len = 0; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + parm = (scsi_Ldefect_data_t *) (cmd + 1); + parm->res1 = parm->res2 = 0; + n_defects *= 4; /* in 4-byte-ints */ + parm->list_len_msb = n_defects >> 8; + parm->list_len_lsb = n_defects; + bcopy((char*)defect_list, (char*)parm->defects, n_defects); + + tgt->cur_cmd = SCSI_CMD_REASSIGN_BLOCKS; + + scsi_go(tgt, sizeof(*cmd) + sizeof(*parm) + (n_defects - 4), 0, FALSE); +} + +void scsi_medium_removal( tgt, allow, ior) + register target_info_t *tgt; + boolean_t allow; + io_req_t ior; +{ + scsi_cmd_medium_removal_t *cmd; + + cmd = (scsi_cmd_medium_removal_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_PREVENT_ALLOW_REMOVAL; + cmd->scsi_cmd_lun_and_lba1 = 0; + cmd->scsi_cmd_lba2 = 0; + cmd->scsi_cmd_lba3 = 0; + cmd->scsi_cmd_pa_prevent = allow ? 0 : 1; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + + tgt->cur_cmd = SCSI_CMD_PREVENT_ALLOW_REMOVAL; + + scsi_go_and_wait(tgt, sizeof(*cmd), 0, ior); +} + +int scsi_format_unit( tgt, mode, vuqe, intlv, ior) + register target_info_t *tgt; + int mode, vuqe; + register unsigned int intlv; + io_req_t ior; +{ + scsi_cmd_format_t *cmd; + char *parms; + + cmd = (scsi_cmd_format_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_FORMAT_UNIT; + cmd->scsi_cmd_lun_and_lba1 = + mode & (SCSI_CMD_FMT_FMTDATA|SCSI_CMD_FMT_CMPLIST|SCSI_CMD_FMT_LIST_TYPE); + cmd->scsi_cmd_lba2 = vuqe; + cmd->scsi_cmd_lba3 = intlv >> 8; + cmd->scsi_cmd_xfer_len = intlv; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + parms = (char*) cmd + 1; + if (ior->io_count) + bcopy(ior->io_data, parms, ior->io_count); + else + bzero(parms, 0xff - sizeof(*cmd)); + + tgt->cur_cmd = SCSI_CMD_FORMAT_UNIT; + + scsi_go_and_wait(tgt, sizeof(*cmd) + ior->io_count, 0, ior); + return tgt->done; +} + + +/* Group 1 Commands */ + +void scsi_long_read( tgt, secno, ior) + register target_info_t *tgt; + register unsigned int secno; + io_req_t ior; +{ + scsi_cmd_long_read_t *cmd; + register unsigned len, n_blks; + unsigned int max_dma_data; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + if (len < tgt->block_size) + len = tgt->block_size; + n_blks = len /tgt->block_size; + + cmd = (scsi_cmd_long_read_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_LONG_READ; + cmd->scsi_cmd_lun_and_relbit = 0; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = n_blks >> 8; + cmd->scsi_cmd_xfer_len_2 = n_blks; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_LONG_READ; + + scsi_go(tgt, sizeof(*cmd), len, FALSE); +} + +void scsi_long_write( tgt, secno, ior) + register target_info_t *tgt; + register unsigned int secno; + io_req_t ior; +{ + scsi_cmd_long_write_t *cmd; + unsigned len; /* in bytes */ + unsigned int max_dma_data, n_blks; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + if (len < tgt->block_size) + len = tgt->block_size; + n_blks = len /tgt->block_size; + + cmd = (scsi_cmd_long_write_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_LONG_WRITE; + cmd->scsi_cmd_lun_and_relbit = 0; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = n_blks >> 8; + cmd->scsi_cmd_xfer_len_2 = n_blks; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_LONG_WRITE; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + +int scdisk_verify( tgt, secno, nsectrs, ior) + register target_info_t *tgt; + int secno, nsectrs; + io_req_t ior; +{ + scsi_cmd_verify_long_t *cmd; + int len; + + len = ior->io_count; + + cmd = (scsi_cmd_verify_long_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_VERIFY_1; + cmd->scsi_cmd_lun_and_relbit = len ? SCSI_CMD_VFY_BYTCHK : 0; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = (nsectrs) >> 8; + cmd->scsi_cmd_xfer_len_2 = nsectrs; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_VERIFY_1; + + scsi_go_and_wait(tgt, sizeof(*cmd) + len, 0, ior); + return tgt->done; +} + + +int scsi_read_defect( tgt, mode, ior) + register target_info_t *tgt; + register unsigned int mode; + io_req_t ior; +{ + scsi_cmd_long_read_t *cmd; + register unsigned len; + + len = ior->io_count; + if (len > 0xffff) + len = 0xffff; + + cmd = (scsi_cmd_read_defect_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_READ_DEFECT_DATA; + cmd->scsi_cmd_lun_and_relbit = 0; + cmd->scsi_cmd_lba1 = mode & 0x1f; + cmd->scsi_cmd_lba2 = 0; + cmd->scsi_cmd_lba3 = 0; + cmd->scsi_cmd_lba4 = 0; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = (len) >> 8; + cmd->scsi_cmd_xfer_len_2 = (len); + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + /* ++ HACK Alert */ +/* tgt->cur_cmd = SCSI_CMD_READ_DEFECT_DATA;*/ + tgt->cur_cmd = SCSI_CMD_LONG_READ; + /* -- HACK Alert */ + + scsi_go(tgt, sizeof(*cmd), len, FALSE); + iowait(ior); + return tgt->done; +} + + +#if 0 /* unused commands */ +scsi_rezero_unit( tgt, ior) + register target_info_t *tgt; + io_req_t ior; +{ + scsi_cmd_rezero_t *cmd; + + cmd = (scsi_cmd_rezero_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_REZERO_UNIT; + cmd->scsi_cmd_lun_and_lba1 = 0; + cmd->scsi_cmd_lba2 = 0; + cmd->scsi_cmd_lba3 = 0; + cmd->scsi_cmd_xfer_len = 0; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + + tgt->cur_cmd = SCSI_CMD_REZERO_UNIT; + + scsi_go_and_wait(tgt, sizeof(*cmd), 0, ior); + +} + +scsi_seek( tgt, where, ior) + register target_info_t *tgt; + register unsigned int where; + io_req_t ior; +{ + scsi_cmd_seek_t *cmd; + + cmd = (scsi_cmd_seek_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_SEEK; + cmd->scsi_cmd_lun_and_lba1 = (where >> 16) & 0x1f; + cmd->scsi_cmd_lba2 = where >> 8; + cmd->scsi_cmd_lba3 = where; + cmd->scsi_cmd_xfer_len = 0; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + + tgt->cur_cmd = SCSI_CMD_SEEK; + + scsi_go_and_wait(tgt, sizeof(*cmd), 0, ior); + +} + +scsi_reserve( tgt, len, id, mode, ior) + register target_info_t *tgt; + register unsigned int len; + unsigned char id; + io_req_t ior; +{ + scsi_cmd_reserve_t *cmd; + + cmd = (scsi_cmd_reserve_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_RESERVE; + cmd->scsi_cmd_lun_and_lba1 = mode & 0x1f; + cmd->scsi_cmd_reserve_id = id; + cmd->scsi_cmd_extent_llen1 = len >> 8; + cmd->scsi_cmd_extent_llen2 = len; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + + tgt->cur_cmd = SCSI_CMD_RESERVE; + + scsi_go_and_wait(tgt, sizeof(*cmd), 0, ior); + +} + +scsi_release( tgt, id, mode, ior) + register target_info_t *tgt; + unsigned char id, mode; + io_req_t ior; +{ + scsi_cmd_release_t *cmd; + + cmd = (scsi_cmd_release_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_RELEASE; + cmd->scsi_cmd_lun_and_lba1 = mode & 0x1f; + cmd->scsi_cmd_reserve_id = id; + cmd->scsi_cmd_lba3 = 0; + cmd->scsi_cmd_xfer_len = 0; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + + tgt->cur_cmd = SCSI_CMD_RELEASE; + + scsi_go_and_wait(tgt, sizeof(*cmd), 0, ior); + +} + + +/* Group 1 Commands */ + +scsi_long_seek( tgt, secno, ior) + register target_info_t *tgt; + io_req_t ior; +{ + scsi_cmd_long_seek_t *cmd; + + cmd = (scsi_cmd_long_seek_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_LONG_SEEK; + cmd->scsi_cmd_lun_and_relbit = 0; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = 0; + cmd->scsi_cmd_xfer_len_2 = 0; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_LONG_SEEK; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + +scsi_write_verify( tgt, secno, ior) + register target_info_t *tgt; + io_req_t ior; +{ + scsi_cmd_write_vfy_t *cmd; + unsigned len; /* in bytes */ + unsigned int max_dma_data, n_blks; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + if (len < tgt->block_size) + len = tgt->block_size; + n_blks = len / tgt->block_size; + + cmd = (scsi_cmd_write_vfy_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_WRITE_AND_VERIFY; + cmd->scsi_cmd_lun_and_relbit = SCSI_CMD_VFY_BYTCHK; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = n_blks >> 8; + cmd->scsi_cmd_xfer_len_2 = n_blks; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_WRITE_AND_VERIFY; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + +scsi_search_data( tgt, secno, how, flags, ior) + register target_info_t *tgt; + io_req_t ior; +{ + scsi_cmd_search_t *cmd; + unsigned len; /* in bytes */ + unsigned int max_dma_data, n_blks; + + max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data; + + if (how != SCSI_CMD_SEARCH_HIGH && + how != SCSI_CMD_SEARCH_EQUAL && + how != SCSI_CMD_SEARCH_LOW) + panic("scsi_search_data"); + + len = ior->io_count; + if (len > max_dma_data) + len = max_dma_data; + n_blks = len / tgt->block_size; + + cmd = (scsi_cmd_search_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = how; + cmd->scsi_cmd_lun_and_relbit = flags & 0x1e; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = n_blks >> 8; + cmd->scsi_cmd_xfer_len_2 = n_blks; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = how; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + + +scsi_set_limits( tgt, secno, nblocks, inhibit, ior) + register target_info_t *tgt; + io_req_t ior; +{ + scsi_cmd_set_limits_t *cmd; + + cmd = (scsi_cmd_set_limits_t*) (tgt->cmd_ptr); + cmd->scsi_cmd_code = SCSI_CMD_SET_LIMITS; + cmd->scsi_cmd_lun_and_relbit = inhibit & 0x3; + cmd->scsi_cmd_lba1 = secno >> 24; + cmd->scsi_cmd_lba2 = secno >> 16; + cmd->scsi_cmd_lba3 = secno >> 8; + cmd->scsi_cmd_lba4 = secno; + cmd->scsi_cmd_xxx = 0; + cmd->scsi_cmd_xfer_len_1 = nblocks >> 8; + cmd->scsi_cmd_xfer_len_2 = nblocks; + cmd->scsi_cmd_ctrl_byte = 0; /* not linked */ + + tgt->cur_cmd = SCSI_CMD_SET_LIMITS; + + scsi_go(tgt, sizeof(*cmd), 0, FALSE); +} + + +#endif + +#ifdef SCSI2 +scsi_lock_cache +scsi_prefetch +scsi_read_defect_data +scsi_sync_cache +scsi_write_same +#endif SCSI2 +#endif /* NSCSI > 0 */ |