cregit-Linux how code gets into the kernel

Release 4.7 drivers/scsi/device_handler/scsi_dh_hp_sw.c

/*
 * 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
 * Copyright (C) 2008 Hannes Reinecke <hare@suse.de>
 *
 * 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 <linux/slab.h>
#include <linux/module.h>
#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


#define HP_SW_PATH_UNINITIALIZED	-1

#define HP_SW_PATH_ACTIVE		0

#define HP_SW_PATH_PASSIVE		1


struct hp_sw_dh_data {
	
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
	
int path_state;
	
int retries;
	
int retry_cnt;
	
struct scsi_device *sdev;
	
activate_complete	callback_fn;
	
void			*callback_data;
};

static int hp_sw_start_stop(struct hp_sw_dh_data *);

/*
 * tur_done - Handle TEST UNIT READY return status
 * @sdev: sdev the command has been sent to
 * @errors: blk error code
 *
 * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path
 */

static int tur_done(struct scsi_device *sdev, unsigned char *sense) { struct scsi_sense_hdr sshdr; int ret; ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); if (!ret) { sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed, no sense available\n", HP_SW_NAME); ret = SCSI_DH_IO; goto done; } switch (sshdr.sense_key) { case UNIT_ATTENTION: ret = SCSI_DH_IMM_RETRY; break; case NOT_READY: if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { /* * LUN not ready - Initialization command required * * This is the passive path */ ret = SCSI_DH_DEV_OFFLINED; break; } /* Fallthrough */ default: sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed, sense %x/%x/%x\n", HP_SW_NAME, sshdr.sense_key, sshdr.asc, sshdr.ascq); break; } done: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
mike christiemike christie7353.68%150.00%
hannes reineckehannes reinecke6346.32%150.00%
Total136100.00%2100.00%

/* * hp_sw_tur - Send TEST UNIT READY * @sdev: sdev command should be sent to * * Use the TEST UNIT READY command to determine * the path state. */
static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) { struct request *req; int ret; retry: req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); if (IS_ERR(req)) return SCSI_DH_RES_TEMP_UNAVAIL; blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); req->cmd[0] = TEST_UNIT_READY; 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 == -EIO) { if (req->sense_len > 0) { ret = tur_done(sdev, h->sense); } else { sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed with %x\n", HP_SW_NAME, req->errors); ret = SCSI_DH_IO; } } else { h->path_state = HP_SW_PATH_ACTIVE; ret = SCSI_DH_OK; } if (ret == SCSI_DH_IMM_RETRY) { blk_put_request(req); goto retry; } if (ret == SCSI_DH_DEV_OFFLINED) { h->path_state = HP_SW_PATH_PASSIVE; ret = SCSI_DH_OK; } blk_put_request(req); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
mike christiemike christie12854.47%233.33%
hannes reineckehannes reinecke9239.15%116.67%
alan d. brunellealan d. brunelle93.83%116.67%
jens axboejens axboe31.28%116.67%
joe lawrencejoe lawrence31.28%116.67%
Total235100.00%6100.00%

/* * start_done - Handle START STOP UNIT return status * @sdev: sdev the command has been sent to * @errors: blk error code */
static int start_done(struct scsi_device *sdev, unsigned char *sense) { struct scsi_sense_hdr sshdr; int rc; rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); if (!rc) { sdev_printk(KERN_WARNING, sdev, "%s: sending start_stop_unit failed, " "no sense available\n", HP_SW_NAME); return SCSI_DH_IO; } switch (sshdr.sense_key) { case NOT_READY: if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { /* * LUN not ready - manual intervention required * * Switch-over in progress, retry. */ rc = SCSI_DH_RETRY; break; } /* fall through */ default: sdev_printk(KERN_WARNING, sdev, "%s: sending start_stop_unit failed, sense %x/%x/%x\n", HP_SW_NAME, sshdr.sense_key, sshdr.asc, sshdr.ascq); rc = SCSI_DH_IO; } return rc; }

Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke126100.00%1100.00%
Total126100.00%1100.00%


static void start_stop_endio(struct request *req, int error) { struct hp_sw_dh_data *h = req->end_io_data; unsigned err = SCSI_DH_OK; if (error || host_byte(req->errors) != DID_OK || msg_byte(req->errors) != COMMAND_COMPLETE) { sdev_printk(KERN_WARNING, h->sdev, "%s: sending start_stop_unit failed with %x\n", HP_SW_NAME, req->errors); err = SCSI_DH_IO; goto done; } if (req->sense_len > 0) { err = start_done(h->sdev, h->sense); if (err == SCSI_DH_RETRY) { err = SCSI_DH_IO; if (--h->retry_cnt) { blk_put_request(req); err = hp_sw_start_stop(h); if (err == SCSI_DH_OK) return; } } } done: req->end_io_data = NULL; __blk_put_request(req->q, req); if (h->callback_fn) { h->callback_fn(h->callback_data, err); h->callback_fn = h->callback_data = NULL; } return; }

Contributors

PersonTokensPropCommitsCommitProp
chandra seetharamanchandra seetharaman17594.09%150.00%
mike snitzermike snitzer115.91%150.00%
Total186100.00%2100.00%

/* * hp_sw_start_stop - Send START STOP UNIT command * @sdev: sdev command should be sent to * * Sending START STOP UNIT activates the SP. */
static int hp_sw_start_stop(struct hp_sw_dh_data *h) { struct request *req; req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); if (IS_ERR(req)) return SCSI_DH_RES_TEMP_UNAVAIL; blk_rq_set_block_pc(req); req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER; req->cmd_len = COMMAND_SIZE(START_STOP); 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; req->end_io_data = h; blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio); return SCSI_DH_OK; }

Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke11985.61%120.00%
chandra seetharamanchandra seetharaman96.47%120.00%
mike christiemike christie53.60%120.00%
jens axboejens axboe32.16%120.00%
joe lawrencejoe lawrence32.16%120.00%
Total139100.00%5100.00%


static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) { struct hp_sw_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->path_state != HP_SW_PATH_ACTIVE) { ret = BLKPREP_KILL; req->cmd_flags |= REQ_QUIET; } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke5196.23%150.00%
christoph hellwigchristoph hellwig23.77%150.00%
Total53100.00%2100.00%

/* * hp_sw_activate - Activate a path * @sdev: sdev on the path to be activated * * The HP Active/Passive firmware is pretty simple; * the passive path reports NOT READY with sense codes * 0x04/0x02; a START STOP UNIT command will then * activate the passive path (and deactivate the * previously active one). */
static int hp_sw_activate(struct scsi_device *sdev, activate_complete fn, void *data) { int ret = SCSI_DH_OK; struct hp_sw_dh_data *h = sdev->handler_data; ret = hp_sw_tur(sdev, h); if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { h->retry_cnt = h->retries; h->callback_fn = fn; h->callback_data = data; ret = hp_sw_start_stop(h); if (ret == SCSI_DH_OK) return 0; h->callback_fn = h->callback_data = NULL; } if (fn) fn(data, ret); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke6253.91%125.00%
chandra seetharamanchandra seetharaman5144.35%250.00%
christoph hellwigchristoph hellwig21.74%125.00%
Total115100.00%4100.00%


static int hp_sw_bus_attach(struct scsi_device *sdev) { struct hp_sw_dh_data *h; int ret; h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; h->path_state = HP_SW_PATH_UNINITIALIZED; h->retries = HP_SW_RETRIES; h->sdev = sdev; ret = hp_sw_tur(sdev, h); if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) goto failed; sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n", HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE? "active":"passive"); sdev->handler_data = h; return 0; failed: kfree(h); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke7762.10%222.22%
mike christiemike christie2620.97%111.11%
christoph hellwigchristoph hellwig1411.29%444.44%
chandra seetharamanchandra seetharaman64.84%111.11%
hillf dantonhillf danton10.81%111.11%
Total124100.00%9100.00%


static void hp_sw_bus_detach( struct scsi_device *sdev ) { kfree(sdev->handler_data); sdev->handler_data = NULL; }

Contributors

PersonTokensPropCommitsCommitProp
christoph hellwigchristoph hellwig937.50%133.33%
hannes reineckehannes reinecke937.50%133.33%
mike christiemike christie625.00%133.33%
Total24100.00%3100.00%

static struct scsi_device_handler hp_sw_dh = { .name = HP_SW_NAME, .module = THIS_MODULE, .attach = hp_sw_bus_attach, .detach = hp_sw_bus_detach, .activate = hp_sw_activate, .prep_fn = hp_sw_prep_fn, };
static int __init hp_sw_init(void) { return scsi_register_device_handler(&hp_sw_dh); }

Contributors

PersonTokensPropCommitsCommitProp
mike christiemike christie16100.00%1100.00%
Total16100.00%1100.00%


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

Contributors

PersonTokensPropCommitsCommitProp
mike christiemike christie15100.00%1100.00%
Total15100.00%1100.00%

module_init(hp_sw_init); module_exit(hp_sw_exit); MODULE_DESCRIPTION("HP Active/Passive driver"); MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
hannes reineckehannes reinecke62147.01%211.76%
mike christiemike christie33225.13%211.76%
chandra seetharamanchandra seetharaman26520.06%211.76%
christoph hellwigchristoph hellwig644.84%423.53%
mike snitzermike snitzer110.83%15.88%
alan d. brunellealan d. brunelle90.68%15.88%
jens axboejens axboe60.45%15.88%
joe lawrencejoe lawrence60.45%15.88%
paul gortmakerpaul gortmaker30.23%15.88%
tejun heotejun heo30.23%15.88%
hillf dantonhillf danton10.08%15.88%
Total1321100.00%17100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}