blob: d87abc5ea4442363ff54ad122554a12a5020965e [file] [log] [blame]
/*
* scst_processor.c
*
* Copyright (C) 2004 - 2018 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004 - 2005 Leonid Stoljar
* Copyright (C) 2007 - 2018 Western Digital Corporation
*
* SCSI medium processor (type 3) dev handler
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2
* of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <scsi/scsi_host.h>
#include <linux/slab.h>
#define LOG_PREFIX "dev_processor"
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst.h>
#else
#include "scst.h"
#endif
#include "scst_dev_handler.h"
#define PROCESSOR_NAME "dev_processor"
#define PROCESSOR_RETRIES 2
static int processor_attach(struct scst_device *);
/*static void processor_detach(struct scst_device *);*/
static int processor_parse(struct scst_cmd *);
/*static int processor_done(struct scst_cmd *);*/
static struct scst_dev_type processor_devtype = {
.name = PROCESSOR_NAME,
.type = TYPE_PROCESSOR,
.threads_num = 1,
.parse_atomic = 1,
/* .dev_done_atomic = 1,*/
.attach = processor_attach,
/* .detach = processor_detach,*/
.parse = processor_parse,
/* .dev_done = processor_done*/
#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING)
.default_trace_flags = SCST_DEFAULT_DEV_LOG_FLAGS,
.trace_flags = &trace_flag,
#endif
};
static int processor_attach(struct scst_device *dev)
{
int res, rc;
int retries;
TRACE_ENTRY();
if (dev->scsi_dev == NULL ||
dev->scsi_dev->type != dev->type) {
PRINT_ERROR("%s", "SCSI device not define or illegal type");
res = -ENODEV;
goto out;
}
/*
* If the device is offline, don't try to read capacity or any
* of the other stuff
*/
if (dev->scsi_dev->sdev_state == SDEV_OFFLINE) {
TRACE_DBG("%s", "Device is offline");
res = -ENODEV;
goto out;
}
retries = SCST_DEV_RETRIES_ON_UA;
do {
TRACE_DBG("%s", "Doing TEST_UNIT_READY");
rc = scsi_test_unit_ready(dev->scsi_dev,
SCST_GENERIC_PROCESSOR_TIMEOUT, PROCESSOR_RETRIES, NULL);
TRACE_DBG("TEST_UNIT_READY done: %x", rc);
} while ((--retries > 0) && rc);
if (rc) {
PRINT_WARNING("Unit not ready: %x", rc);
/* Let's try not to be too smart and continue processing */
}
res = scst_obtain_device_parameters(dev, NULL);
if (res != 0) {
PRINT_ERROR("Failed to obtain control parameters for device "
"%s", dev->virt_name);
goto out;
}
out:
TRACE_EXIT();
return res;
}
#if 0
void processor_detach(struct scst_device *dev)
{
TRACE_ENTRY();
TRACE_EXIT();
return;
}
#endif
static int processor_parse(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT, rc;
rc = scst_processor_generic_parse(cmd);
if (rc != 0) {
res = scst_get_cmd_abnormal_done_state(cmd);
goto out;
}
cmd->retries = SCST_PASSTHROUGH_RETRIES;
out:
return res;
}
#if 0
int processor_done(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT;
TRACE_ENTRY();
/*
* SCST sets good defaults for cmd->is_send_status and
* cmd->resp_data_len based on cmd->status and cmd->data_direction,
* therefore change them only if necessary.
*/
#if 0
switch (cmd->cdb[0]) {
default:
/* It's all good */
break;
}
#endif
TRACE_EXIT();
return res;
}
#endif
static int __init processor_init(void)
{
int res = 0;
TRACE_ENTRY();
processor_devtype.module = THIS_MODULE;
res = scst_register_dev_driver(&processor_devtype);
if (res < 0)
goto out;
out:
TRACE_EXIT_RES(res);
return res;
}
static void __exit processor_exit(void)
{
TRACE_ENTRY();
scst_unregister_dev_driver(&processor_devtype);
TRACE_EXIT();
return;
}
module_init(processor_init);
module_exit(processor_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI medium processor (type 3) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);
MODULE_IMPORT_NS(SCST);