From 5a4256759a1a8e4dd064abb74d874589704ebabf Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 27 Apr 2010 20:35:14 +0200 Subject: [PATCH 2/2] added scsi support with libusal --- libhimd/himd_scsi.c | 270 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 270 insertions(+), 0 deletions(-) create mode 100644 libhimd/himd_scsi.c diff --git a/libhimd/himd_scsi.c b/libhimd/himd_scsi.c new file mode 100644 index 0000000..247c17a --- /dev/null +++ b/libhimd/himd_scsi.c @@ -0,0 +1,270 @@ +#include + +#include "himd.h" +#include "himd_private.h" + +#define _(x) (x) + +#ifdef CONFIG_WITH_LIBUSAL +#include + +#define SCSI_TIMEOUT 20 +#define ALLOW_REMOVAL 0 +#define PREVENT_REMOVAL 1 +#define MAX_BUFFER_SIZE 200 /* final value depends on max value of supported commands */ + +static int prevent_removal(struct sdev * sdev, int prevent) +{ + struct usal_cmd * scmd = sdev->usalp->scmd; + + memset(sdev->usalp->errstr, 0x0, sizeof(sdev->usalp->errstr)); + memset(scmd, 0, sizeof(struct usal_cmd)); + scmd->addr = (caddr_t)0; + scmd->size = 0; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb.g0_cdb.cmd = 0x1E; + scmd->cdb.g0_cdb.lun = usal_lun(sdev->usalp); + scmd->cdb.g0_cdb.count = prevent & 1; + + sdev->usalp->cmdname = "allow / prevent removal"; + + return usal_cmd(sdev->usalp); +} + +static int test_unit_ready(struct sdev * sdev) +{ + struct usal_cmd * scmd = sdev->usalp->scmd; + + memset(sdev->usalp->errstr, 0x0, sizeof(sdev->usalp->errstr)); + memset(scmd, 0, sizeof(struct usal_cmd)); + scmd->addr = (caddr_t)0; + scmd->size = 0; + scmd->flags = SCG_DISRE_ENA; + scmd->cdb_len = SC_G0_CDBLEN; + scmd->sense_len = CCS_SENSE_LEN; + scmd->cdb.g0_cdb.cmd = SC_TEST_UNIT_READY; + scmd->cdb.g0_cdb.lun = usal_lun(sdev->usalp); + + sdev->usalp->cmdname = "test unit ready"; + + return usal_cmd(sdev->usalp); +} + +static int send_command(struct sdev * sdev, const char * command, int len, char * name) +{ + struct usal_cmd * scmd = sdev->usalp->scmd; + + memset(sdev->usalp->errstr, 0x0, sizeof(sdev->usalp->errstr)); + usal_settimeout(sdev->usalp, SCSI_TIMEOUT); + sdev->usalp->cmdname = name; + + memset(scmd, 0, sizeof(struct usal_cmd)); + scmd->addr = (caddr_t)0; + scmd->size = 0; + scmd->cdb_len = len; + scmd->sense_len = CCS_SENSE_LEN; + scmd->flags = SCG_DISRE_ENA; + memcpy(scmd->cdb.cmd_cdb, command, scmd->cdb_len); + + return usal_cmd(sdev->usalp); +} + +static int send_command_with_buffer(struct sdev * sdev, const char * command, int len, char * name, + char * outbuf, int outlen, int mode) +{ + struct usal_cmd * scmd = sdev->usalp->scmd; + + memset(sdev->usalp->errstr, 0x0, sizeof(sdev->usalp->errstr)); + usal_settimeout(sdev->usalp, SCSI_TIMEOUT); + sdev->usalp->cmdname = name; + + memset(scmd, 0, sizeof(struct usal_cmd)); + scmd->addr = (caddr_t)outbuf; + scmd->size = outlen; + scmd->cdb_len = len; + scmd->sense_len = CCS_SENSE_LEN; + scmd->flags = mode | SCG_DISRE_ENA; + memcpy(scmd->cdb.cmd_cdb, command, scmd->cdb_len); + + return usal_cmd(sdev->usalp); +} + +void himdll_reset_device(struct sdev * sdev) /* clear pointer on uninitialized struct sdev */ +{ + sdev->usalp = NULL; +} + +int himdll_open_device(struct sdev * sdev, int mode, struct himderrinfo * status) +{ + if(sdev->usalp != NULL) /* limited to one scsi device per session, we should check if we */ + { /* want to support multiple devices at the same time */ + set_status_const(status, HIMD_ERROR_DEVICE_ALREADY_OPENED, + _("Canīt open scsi device, another instance is already running")); + return -1; + } + + sdev->usalp = usal_open(sdev->device, sdev->errstr, sizeof(sdev->errstr), 0, 0); + if(!sdev->usalp) + goto clean; + + if(sdev->usalp->addr.scsibus == -2 && sdev->usalp->addr.target == -2) + { + if(!usal__open(sdev->usalp, sdev->device)) + { + himdll_close_device(sdev); + goto clean; + } + } + sdev->usalp->silent = mode; + prevent_removal(sdev, PREVENT_REMOVAL); + return 0; + +clean: + set_status_const(status, HIMD_ERROR_CANT_OPEN_SCSI_DEVICE, _("Canīt open scsi device")); + return -1; +} + +int himdll_send_format_cmd(struct sdev * sdev, struct himderrinfo * status) +{ + static const char cmd_formathimd[12] = {0xC2,0,0,0,3,0,0,0,0,0,0,0}; + + if(!sdev->usalp) + { + set_status_const(status, HIMD_ERROR_DEVICE_NOT_OPENED, + _("Canīt send format command: scsi device not opened")); + return -1; + } + + if(send_command(sdev, cmd_formathimd, sizeof(cmd_formathimd), "himd format") < 0) + { + set_status_printf(status, HIMD_ERROR_SCSI_COMMAND_FAILED, _("Canīt format himd: %s"), + usal_sensemsg(0, usal_sense_code(sdev->usalp), usal_sense_qual(sdev->usalp), + NULL, sdev->usalp->errstr, sizeof(sdev->usalp->errstr))); + return -1; + } + return 0; +} + +int himdll_wait_for_unit_ready(struct sdev * sdev, struct himderrinfo * status) +{ + int c, k; + int ret = 0; + + if(!sdev->usalp) + { + set_status_const(status, HIMD_ERROR_DEVICE_NOT_OPENED, + _("Canīt send test unit ready command: scsi device not opened")); + return -1; + } + + if (test_unit_ready(sdev) >= 0) + return 0; + + while((ret = test_unit_ready(sdev)) < 0) + { + if (sdev->usalp->scmd->scb.busy == 0) + { + c = usal_sense_code(sdev->usalp); /* Abort if it does not make sense to wait. */ + k = usal_sense_key(sdev->usalp); /* 0x30 == Cannot read medium ; 0x3A == Medium not present*/ + if ((k == SC_NOT_READY && (c == 0x3A || c == 0x30)) ||(k == SC_MEDIUM_ERROR)) + break; + } + } + + if(ret < 0) + { + set_status_printf(status, HIMD_ERROR_DEVICE_NOT_READY, + _("Error waiting for unit ready: &s"), + usal_sensemsg(0, usal_sense_code(sdev->usalp), usal_sense_qual(sdev->usalp), + NULL, sdev->usalp->errstr, sizeof(sdev->usalp->errstr))); + return -1; + } + return 0; +} + +const char * himdll_get_discid(struct sdev * sdev, char * buf, int len, struct himderrinfo * status) +{ + int length; + static const char cmd_getdiscid[12] = {0xA4,0,0,0,0,0,0,0xBD,0,0x12,0x3D,0}; + char buffer[MAX_BUFFER_SIZE]; + + if(!sdev->usalp) + { + set_status_const(status, HIMD_ERROR_DEVICE_NOT_OPENED, + _("Canīt read disc id: scsi device not opened")); + return NULL; + } + + memset(buffer, 0x0, sizeof(buffer)); + memset(buf, 0x0, len); + + if(send_command_with_buffer(sdev, cmd_getdiscid, sizeof(cmd_getdiscid), "get disc id", buffer, + 0x12, SCG_RECV_DATA) < 0) + { + set_status_printf(status, HIMD_ERROR_SCSI_COMMAND_FAILED, _("Can't read disc id: %s"), + usal_sensemsg(0, usal_sense_code(sdev->usalp), usal_sense_qual(sdev->usalp), + NULL, sdev->usalp->errstr, sizeof(sdev->usalp->errstr))); + return NULL; + } + + length = ((buffer[0] & 0xFF) * 265) + (buffer[1] & 0xFF); + if(len < length) + { + set_status_printf(status, HIMD_ERROR_SCSI_COMMAND_FAILED, + _("Canīt read disc id: output buffer too short, minimum of %d bytes needed"), + length); + return NULL; + } + + memcpy(buf, buffer+2, length); + return buf; +} + +void himdll_close_device(struct sdev * sdev) +{ + if(!sdev->usalp) + return; + prevent_removal(sdev, ALLOW_REMOVAL); + usal__close(sdev->usalp); + himdll_reset_device(sdev); +} +#else + +void himdll_reset_device(struct sdev * sdev) +{ +} + +int himdll_open_device(struct sdev * sdev, int mode, struct himderrinfo * status) +{ + set_status_const(status, HIMD_ERROR_DISABLED_FEATURE, + _("Can't open scsi device: Compiled without libusal library")); + return -1; +} + +int himdll_send_format_cmd(struct sdev * sdev, struct himderrinfo * status); +{ + set_status_const(status, HIMD_ERROR_DISABLED_FEATURE, + _("Can't send scsi commands: Compiled without libusal library")); + return -1; +} + +int himdll_wait_for_unit_ready(struct sdev * sdev, struct himderrinfo * status); +{ + return -1; +} + +const char * himdll_get_discid(struct sdev * sdev, char * buf, int len, struct himderrinfo * status) +{ + set_status_const(status, HIMD_ERROR_DISABLED_FEATURE, + _("Can't send scsi commands: Compiled without libusal library")); + return NULL; +} + +void himdll_close_device(struct sdev * sdev); +{ +} + +#endif + -- 1.6.4.msysgit.0