blob: 4a0938ffd194a1e1672b6e2147898b63a44958a3 [file] [log] [blame]
/*
* scst_raid.c
*
* Copyright (C) 2004 - 2018 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004 - 2005 Leonid Stoljar
* Copyright (C) 2007 - 2018 Western Digital Corporation
*
* SCSI raid(controller) (type 0xC) 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.
*/
#define LOG_PREFIX "dev_raid"
#include <scsi/scsi_host.h>
#include <linux/slab.h>
#ifdef INSIDE_KERNEL_TREE
#include <scst/scst.h>
#else
#include "scst.h"
#endif
#include "scst_dev_handler.h"
#define RAID_NAME "dev_raid"
#define RAID_RETRIES 2
static int raid_attach(struct scst_device *);
/* static void raid_detach(struct scst_device *); */
static int raid_parse(struct scst_cmd *);
/* static int raid_done(struct scst_cmd *); */
static struct scst_dev_type raid_devtype = {
.name = RAID_NAME,
.type = TYPE_RAID,
.threads_num = 1,
.parse_atomic = 1,
/* .dev_done_atomic = 1,*/
.attach = raid_attach,
/* .detach = raid_detach,*/
.parse = raid_parse,
/* .dev_done = raid_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 raid_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_RAID_TIMEOUT, RAID_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 raid_detach(struct scst_device *dev)
{
TRACE_ENTRY();
TRACE_EXIT();
return;
}
#endif
static int raid_parse(struct scst_cmd *cmd)
{
int res = SCST_CMD_STATE_DEFAULT, rc;
rc = scst_raid_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 raid_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 raid_init(void)
{
int res = 0;
TRACE_ENTRY();
raid_devtype.module = THIS_MODULE;
res = scst_register_dev_driver(&raid_devtype);
if (res < 0)
goto out;
out:
TRACE_EXIT_RES(res);
return res;
}
static void __exit raid_exit(void)
{
TRACE_ENTRY();
scst_unregister_dev_driver(&raid_devtype);
TRACE_EXIT();
return;
}
module_init(raid_init);
module_exit(raid_exit);
MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("SCSI raid(controller) (type 0xC) dev handler for SCST");
MODULE_VERSION(SCST_VERSION_STRING);
MODULE_IMPORT_NS(SCST);