Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 101481
b: refs/heads/master
c: f6dd337
h: refs/heads/master
i:
  101479: 2bbdb43
v: v3
  • Loading branch information
Mike Christie authored and James Bottomley committed Jun 5, 2008
1 parent c2e6624 commit a965d91
Show file tree
Hide file tree
Showing 4 changed files with 212 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fbd7ab3eb53a3b88fefa7873139a62e439860155
refs/heads/master: f6dd337ee4c440f29a873da3779eb3af44bd1623
8 changes: 8 additions & 0 deletions trunk/drivers/scsi/device_handler/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ config SCSI_DH_RDAC
depends on SCSI_DH
help
If you have a LSI RDAC select y. Otherwise, say N.

config SCSI_DH_HP_SW
tristate "HP/COMPAQ MSA Device Handler"
depends on SCSI_DH
help
If you have a HP/COMPAQ MSA device that requires START_STOP to
be sent to start it and cannot upgrade the firmware then select y.
Otherwise, say N.
1 change: 1 addition & 0 deletions trunk/drivers/scsi/device_handler/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
#
obj-$(CONFIG_SCSI_DH) += scsi_dh.o
obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o
obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o
202 changes: 202 additions & 0 deletions trunk/drivers/scsi/device_handler/scsi_dh_hp_sw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be
* upgraded.
*
* Copyright (C) 2006 Red Hat, Inc. All rights reserved.
* Copyright (C) 2006 Mike Christie
*
* 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; either version 2, or (at your option)
* any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dh.h>

#define HP_SW_NAME "hp_sw"

#define HP_SW_TIMEOUT (60 * HZ)
#define HP_SW_RETRIES 3

struct hp_sw_dh_data {
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int retries;
};

static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
{
struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
BUG_ON(scsi_dh_data == NULL);
return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
}

static int hp_sw_done(struct scsi_device *sdev)
{
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
struct scsi_sense_hdr sshdr;
int rc;

sdev_printk(KERN_INFO, sdev, "hp_sw_done\n");

rc = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sshdr);
if (!rc)
goto done;
switch (sshdr.sense_key) {
case NOT_READY:
if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) {
rc = SCSI_DH_RETRY;
h->retries++;
break;
}
/* fall through */
default:
h->retries++;
rc = SCSI_DH_IMM_RETRY;
}

done:
if (rc == SCSI_DH_OK || rc == SCSI_DH_IO)
h->retries = 0;
else if (h->retries > HP_SW_RETRIES) {
h->retries = 0;
rc = SCSI_DH_IO;
}
return rc;
}

static int hp_sw_activate(struct scsi_device *sdev)
{
struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
struct request *req;
int ret = SCSI_DH_RES_TEMP_UNAVAIL;

req = blk_get_request(sdev->request_queue, WRITE, GFP_ATOMIC);
if (!req)
goto done;

sdev_printk(KERN_INFO, sdev, "sending START_STOP.");

req->cmd_type = REQ_TYPE_BLOCK_PC;
req->cmd_flags |= REQ_FAILFAST;
req->cmd_len = COMMAND_SIZE(START_STOP);
memset(req->cmd, 0, MAX_COMMAND_SIZE);
req->cmd[0] = START_STOP;
req->cmd[4] = 1; /* Start spin cycle */
req->timeout = HP_SW_TIMEOUT;
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
req->sense_len = 0;

ret = blk_execute_rq(req->q, NULL, req, 1);
if (!ret) /* SUCCESS */
ret = hp_sw_done(sdev);
else
ret = SCSI_DH_IO;
done:
return ret;
}

static const struct {
char *vendor;
char *model;
} hp_sw_dh_data_list[] = {
{"COMPAQ", "MSA"},
{"HP", "HSV"},
{"DEC", "HSG80"},
{NULL, NULL},
};

static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);

static struct scsi_device_handler hp_sw_dh = {
.name = HP_SW_NAME,
.module = THIS_MODULE,
.nb.notifier_call = hp_sw_bus_notify,
.activate = hp_sw_activate,
};

static int hp_sw_bus_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct device *dev = data;
struct scsi_device *sdev = to_scsi_device(dev);
struct scsi_dh_data *scsi_dh_data;
int i, found = 0;
unsigned long flags;

if (action == BUS_NOTIFY_ADD_DEVICE) {
for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
strlen(hp_sw_dh_data_list[i].vendor)) &&
!strncmp(sdev->model, hp_sw_dh_data_list[i].model,
strlen(hp_sw_dh_data_list[i].model))) {
found = 1;
break;
}
}
if (!found)
goto out;

scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
HP_SW_NAME);
goto out;
}

scsi_dh_data->scsi_dh = &hp_sw_dh;
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
sdev->scsi_dh_data = scsi_dh_data;
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
try_module_get(THIS_MODULE);

sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
if (sdev->scsi_dh_data == NULL ||
sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
goto out;

spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
scsi_dh_data = sdev->scsi_dh_data;
sdev->scsi_dh_data = NULL;
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
module_put(THIS_MODULE);

sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);

kfree(scsi_dh_data);
}

out:
return 0;
}

static int __init hp_sw_init(void)
{
return scsi_register_device_handler(&hp_sw_dh);
}

static void __exit hp_sw_exit(void)
{
scsi_unregister_device_handler(&hp_sw_dh);
}

module_init(hp_sw_init);
module_exit(hp_sw_exit);

MODULE_DESCRIPTION("HP MSA 1000");
MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
MODULE_LICENSE("GPL");

0 comments on commit a965d91

Please sign in to comment.