Skip to content

Commit

Permalink
[SCSI] scsi_dh: Update RDAC device handler
Browse files Browse the repository at this point in the history
This patch updates the RDAC device handler to
refuse to attach to devices not supporting the
RDAC vpd pages.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Hannes Reinecke authored and James Bottomley committed Jul 26, 2008
1 parent 2aef6d5 commit ca9f008
Showing 1 changed file with 94 additions and 69 deletions.
163 changes: 94 additions & 69 deletions drivers/scsi/device_handler/scsi_dh_rdac.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ struct rdac_dh_data {
#define RDAC_STATE_ACTIVE 0
#define RDAC_STATE_PASSIVE 1
unsigned char state;

#define RDAC_LUN_UNOWNED 0
#define RDAC_LUN_OWNED 1
#define RDAC_LUN_AVT 2
char lun_state;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
union {
struct c2_inquiry c2;
Expand All @@ -182,6 +187,13 @@ struct rdac_dh_data {
} inq;
};

static const char *lun_state[] =
{
"unowned",
"owned",
"owned (AVT mode)",
};

static LIST_HEAD(ctlr_list);
static DEFINE_SPINLOCK(list_lock);

Expand All @@ -197,27 +209,23 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
{
struct request *rq;
struct request_queue *q = sdev->request_queue;
struct rdac_dh_data *h = get_rdac_data(sdev);

rq = blk_get_request(q, rw, GFP_KERNEL);
rq = blk_get_request(q, rw, GFP_NOIO);

if (!rq) {
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_get_request failed.\n");
return NULL;
}

if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_KERNEL)) {
if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) {
blk_put_request(rq);
sdev_printk(KERN_INFO, sdev,
"get_rdac_req: blk_rq_map_kern failed.\n");
return NULL;
}

memset(&rq->cmd, 0, BLK_MAX_CDB);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
memset(rq->cmd, 0, BLK_MAX_CDB);

rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
Expand All @@ -227,12 +235,12 @@ static struct request *get_rdac_req(struct scsi_device *sdev,
return rq;
}

static struct request *rdac_failover_get(struct scsi_device *sdev)
static struct request *rdac_failover_get(struct scsi_device *sdev,
struct rdac_dh_data *h)
{
struct request *rq;
struct rdac_mode_common *common;
unsigned data_size;
struct rdac_dh_data *h = get_rdac_data(sdev);

if (h->ctlr->use_ms10) {
struct rdac_pg_expanded *rdac_pg;
Expand Down Expand Up @@ -277,6 +285,10 @@ static struct request *rdac_failover_get(struct scsi_device *sdev)
}
rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);

rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;

return rq;
}

Expand Down Expand Up @@ -321,11 +333,10 @@ static struct rdac_controller *get_controller(u8 *subsys_id, u8 *slot_id)
}

static int submit_inquiry(struct scsi_device *sdev, int page_code,
unsigned int len)
unsigned int len, struct rdac_dh_data *h)
{
struct request *rq;
struct request_queue *q = sdev->request_queue;
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_RES_TEMP_UNAVAIL;

rq = get_rdac_req(sdev, &h->inq, len, READ);
Expand All @@ -338,59 +349,68 @@ static int submit_inquiry(struct scsi_device *sdev, int page_code,
rq->cmd[2] = page_code;
rq->cmd[4] = len;
rq->cmd_len = COMMAND_SIZE(INQUIRY);

rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;

err = blk_execute_rq(q, NULL, rq, 1);
if (err == -EIO)
err = SCSI_DH_IO;

blk_put_request(rq);
done:
return err;
}

static int get_lun(struct scsi_device *sdev)
static int get_lun(struct scsi_device *sdev, struct rdac_dh_data *h)
{
int err;
struct c8_inquiry *inqp;
struct rdac_dh_data *h = get_rdac_data(sdev);

err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry));
err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h);
if (err == SCSI_DH_OK) {
inqp = &h->inq.c8;
h->lun = inqp->lun[7]; /* currently it uses only one byte */
if (inqp->page_code != 0xc8)
return SCSI_DH_NOSYS;
if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' ||
inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd')
return SCSI_DH_NOSYS;
h->lun = scsilun_to_int((struct scsi_lun *)inqp->lun);
}
return err;
}

#define RDAC_OWNED 0
#define RDAC_UNOWNED 1
#define RDAC_FAILED 2
static int check_ownership(struct scsi_device *sdev)
static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
{
int err;
struct c9_inquiry *inqp;
struct rdac_dh_data *h = get_rdac_data(sdev);

err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry));
err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
if (err == SCSI_DH_OK) {
err = RDAC_UNOWNED;
inqp = &h->inq.c9;
/*
* If in AVT mode or if the path already owns the LUN,
* return RDAC_OWNED;
*/
if (((inqp->avte_cvp >> 7) == 0x1) ||
((inqp->avte_cvp & 0x1) != 0))
err = RDAC_OWNED;
} else
err = RDAC_FAILED;
if ((inqp->avte_cvp >> 7) == 0x1) {
/* LUN in AVT mode */
sdev_printk(KERN_NOTICE, sdev,
"%s: AVT mode detected\n",
RDAC_NAME);
h->lun_state = RDAC_LUN_AVT;
} else if ((inqp->avte_cvp & 0x1) != 0) {
/* LUN was owned by the controller */
h->lun_state = RDAC_LUN_OWNED;
}
}

return err;
}

static int initialize_controller(struct scsi_device *sdev)
static int initialize_controller(struct scsi_device *sdev,
struct rdac_dh_data *h)
{
int err;
struct c4_inquiry *inqp;
struct rdac_dh_data *h = get_rdac_data(sdev);

err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry));
err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h);
if (err == SCSI_DH_OK) {
inqp = &h->inq.c4;
h->ctlr = get_controller(inqp->subsys_id, inqp->slot_id);
Expand All @@ -400,13 +420,12 @@ static int initialize_controller(struct scsi_device *sdev)
return err;
}

static int set_mode_select(struct scsi_device *sdev)
static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
{
int err;
struct c2_inquiry *inqp;
struct rdac_dh_data *h = get_rdac_data(sdev);

err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry));
err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h);
if (err == SCSI_DH_OK) {
inqp = &h->inq.c2;
/*
Expand All @@ -421,13 +440,13 @@ static int set_mode_select(struct scsi_device *sdev)
return err;
}

static int mode_select_handle_sense(struct scsi_device *sdev)
static int mode_select_handle_sense(struct scsi_device *sdev,
unsigned char *sensebuf)
{
struct scsi_sense_hdr sense_hdr;
struct rdac_dh_data *h = get_rdac_data(sdev);
int sense, err = SCSI_DH_IO, ret;

ret = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr);
if (!ret)
goto done;

Expand All @@ -451,24 +470,25 @@ static int mode_select_handle_sense(struct scsi_device *sdev)
return err;
}

static int send_mode_select(struct scsi_device *sdev)
static int send_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h)
{
struct request *rq;
struct request_queue *q = sdev->request_queue;
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_RES_TEMP_UNAVAIL;

rq = rdac_failover_get(sdev);
rq = rdac_failover_get(sdev, h);
if (!rq)
goto done;

sdev_printk(KERN_INFO, sdev, "queueing MODE_SELECT command.\n");

err = blk_execute_rq(q, NULL, rq, 1);
if (err != SCSI_DH_OK)
err = mode_select_handle_sense(sdev);
err = mode_select_handle_sense(sdev, h->sense);
if (err == SCSI_DH_OK)
h->state = RDAC_STATE_ACTIVE;

blk_put_request(rq);
done:
return err;
}
Expand All @@ -478,38 +498,23 @@ static int rdac_activate(struct scsi_device *sdev)
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_OK;

if (h->lun == UNINITIALIZED_LUN) {
err = get_lun(sdev);
if (err != SCSI_DH_OK)
goto done;
}

err = check_ownership(sdev);
switch (err) {
case RDAC_UNOWNED:
break;
case RDAC_OWNED:
err = SCSI_DH_OK;
goto done;
case RDAC_FAILED:
default:
err = SCSI_DH_IO;
err = check_ownership(sdev, h);
if (err != SCSI_DH_OK)
goto done;
}

if (!h->ctlr) {
err = initialize_controller(sdev);
err = initialize_controller(sdev, h);
if (err != SCSI_DH_OK)
goto done;
}

if (h->ctlr->use_ms10 == -1) {
err = set_mode_select(sdev);
err = set_mode_select(sdev, h);
if (err != SCSI_DH_OK)
goto done;
}

err = send_mode_select(sdev);
if (h->lun_state == RDAC_LUN_UNOWNED)
err = send_mode_select(sdev, h);
done:
return err;
}
Expand Down Expand Up @@ -606,11 +611,12 @@ static int rdac_bus_attach(struct scsi_device *sdev)
struct scsi_dh_data *scsi_dh_data;
struct rdac_dh_data *h;
unsigned long flags;
int err;

scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
+ sizeof(*h) , GFP_KERNEL);
if (!scsi_dh_data) {
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
RDAC_NAME);
return 0;
}
Expand All @@ -619,14 +625,33 @@ static int rdac_bus_attach(struct scsi_device *sdev)
h = (struct rdac_dh_data *) scsi_dh_data->buf;
h->lun = UNINITIALIZED_LUN;
h->state = RDAC_STATE_ACTIVE;

err = get_lun(sdev, h);
if (err != SCSI_DH_OK)
goto failed;

err = check_ownership(sdev, h);
if (err != SCSI_DH_OK)
goto failed;

if (!try_module_get(THIS_MODULE))
goto failed;

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", RDAC_NAME);
sdev_printk(KERN_NOTICE, sdev,
"%s: LUN %d (%s)\n",
RDAC_NAME, h->lun, lun_state[(int)h->lun_state]);

return 0;

failed:
kfree(scsi_dh_data);
sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
RDAC_NAME);
return -EINVAL;
}

static void rdac_bus_detach( struct scsi_device *sdev )
Expand All @@ -645,7 +670,7 @@ static void rdac_bus_detach( struct scsi_device *sdev )
kref_put(&h->ctlr->kref, release_controller);
kfree(scsi_dh_data);
module_put(THIS_MODULE);
sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", RDAC_NAME);
sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
}


Expand Down

0 comments on commit ca9f008

Please sign in to comment.