0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <scsi/scsi.h>
0014 #include <scsi/scsi_dbg.h>
0015 #include <scsi/scsi_eh.h>
0016 #include <scsi/scsi_dh.h>
0017
0018 #define HP_SW_NAME "hp_sw"
0019
0020 #define HP_SW_TIMEOUT (60 * HZ)
0021 #define HP_SW_RETRIES 3
0022
0023 #define HP_SW_PATH_UNINITIALIZED -1
0024 #define HP_SW_PATH_ACTIVE 0
0025 #define HP_SW_PATH_PASSIVE 1
0026
0027 struct hp_sw_dh_data {
0028 int path_state;
0029 int retries;
0030 int retry_cnt;
0031 struct scsi_device *sdev;
0032 };
0033
0034 static int hp_sw_start_stop(struct hp_sw_dh_data *);
0035
0036
0037
0038
0039
0040
0041
0042
0043 static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h,
0044 struct scsi_sense_hdr *sshdr)
0045 {
0046 int ret = SCSI_DH_IO;
0047
0048 switch (sshdr->sense_key) {
0049 case UNIT_ATTENTION:
0050 ret = SCSI_DH_IMM_RETRY;
0051 break;
0052 case NOT_READY:
0053 if (sshdr->asc == 0x04 && sshdr->ascq == 2) {
0054
0055
0056
0057
0058
0059 h->path_state = HP_SW_PATH_PASSIVE;
0060 ret = SCSI_DH_OK;
0061 break;
0062 }
0063 fallthrough;
0064 default:
0065 sdev_printk(KERN_WARNING, sdev,
0066 "%s: sending tur failed, sense %x/%x/%x\n",
0067 HP_SW_NAME, sshdr->sense_key, sshdr->asc,
0068 sshdr->ascq);
0069 break;
0070 }
0071 return ret;
0072 }
0073
0074
0075
0076
0077
0078
0079
0080
0081 static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h)
0082 {
0083 unsigned char cmd[6] = { TEST_UNIT_READY };
0084 struct scsi_sense_hdr sshdr;
0085 int ret = SCSI_DH_OK, res;
0086 blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
0087 REQ_FAILFAST_DRIVER;
0088
0089 retry:
0090 res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
0091 HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL);
0092 if (res) {
0093 if (scsi_sense_valid(&sshdr))
0094 ret = tur_done(sdev, h, &sshdr);
0095 else {
0096 sdev_printk(KERN_WARNING, sdev,
0097 "%s: sending tur failed with %x\n",
0098 HP_SW_NAME, res);
0099 ret = SCSI_DH_IO;
0100 }
0101 } else {
0102 h->path_state = HP_SW_PATH_ACTIVE;
0103 ret = SCSI_DH_OK;
0104 }
0105 if (ret == SCSI_DH_IMM_RETRY)
0106 goto retry;
0107
0108 return ret;
0109 }
0110
0111
0112
0113
0114
0115
0116
0117 static int hp_sw_start_stop(struct hp_sw_dh_data *h)
0118 {
0119 unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 };
0120 struct scsi_sense_hdr sshdr;
0121 struct scsi_device *sdev = h->sdev;
0122 int res, rc = SCSI_DH_OK;
0123 int retry_cnt = HP_SW_RETRIES;
0124 blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
0125 REQ_FAILFAST_DRIVER;
0126
0127 retry:
0128 res = scsi_execute(sdev, cmd, DMA_NONE, NULL, 0, NULL, &sshdr,
0129 HP_SW_TIMEOUT, HP_SW_RETRIES, req_flags, 0, NULL);
0130 if (res) {
0131 if (!scsi_sense_valid(&sshdr)) {
0132 sdev_printk(KERN_WARNING, sdev,
0133 "%s: sending start_stop_unit failed, "
0134 "no sense available\n", HP_SW_NAME);
0135 return SCSI_DH_IO;
0136 }
0137 switch (sshdr.sense_key) {
0138 case NOT_READY:
0139 if (sshdr.asc == 0x04 && sshdr.ascq == 3) {
0140
0141
0142
0143
0144
0145 if (--retry_cnt)
0146 goto retry;
0147 rc = SCSI_DH_RETRY;
0148 break;
0149 }
0150 fallthrough;
0151 default:
0152 sdev_printk(KERN_WARNING, sdev,
0153 "%s: sending start_stop_unit failed, "
0154 "sense %x/%x/%x\n", HP_SW_NAME,
0155 sshdr.sense_key, sshdr.asc, sshdr.ascq);
0156 rc = SCSI_DH_IO;
0157 }
0158 }
0159 return rc;
0160 }
0161
0162 static blk_status_t hp_sw_prep_fn(struct scsi_device *sdev, struct request *req)
0163 {
0164 struct hp_sw_dh_data *h = sdev->handler_data;
0165
0166 if (h->path_state != HP_SW_PATH_ACTIVE) {
0167 req->rq_flags |= RQF_QUIET;
0168 return BLK_STS_IOERR;
0169 }
0170
0171 return BLK_STS_OK;
0172 }
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184 static int hp_sw_activate(struct scsi_device *sdev,
0185 activate_complete fn, void *data)
0186 {
0187 int ret = SCSI_DH_OK;
0188 struct hp_sw_dh_data *h = sdev->handler_data;
0189
0190 ret = hp_sw_tur(sdev, h);
0191
0192 if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE)
0193 ret = hp_sw_start_stop(h);
0194
0195 if (fn)
0196 fn(data, ret);
0197 return 0;
0198 }
0199
0200 static int hp_sw_bus_attach(struct scsi_device *sdev)
0201 {
0202 struct hp_sw_dh_data *h;
0203 int ret;
0204
0205 h = kzalloc(sizeof(*h), GFP_KERNEL);
0206 if (!h)
0207 return SCSI_DH_NOMEM;
0208 h->path_state = HP_SW_PATH_UNINITIALIZED;
0209 h->retries = HP_SW_RETRIES;
0210 h->sdev = sdev;
0211
0212 ret = hp_sw_tur(sdev, h);
0213 if (ret != SCSI_DH_OK)
0214 goto failed;
0215 if (h->path_state == HP_SW_PATH_UNINITIALIZED) {
0216 ret = SCSI_DH_NOSYS;
0217 goto failed;
0218 }
0219
0220 sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
0221 HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
0222 "active":"passive");
0223
0224 sdev->handler_data = h;
0225 return SCSI_DH_OK;
0226 failed:
0227 kfree(h);
0228 return ret;
0229 }
0230
0231 static void hp_sw_bus_detach( struct scsi_device *sdev )
0232 {
0233 kfree(sdev->handler_data);
0234 sdev->handler_data = NULL;
0235 }
0236
0237 static struct scsi_device_handler hp_sw_dh = {
0238 .name = HP_SW_NAME,
0239 .module = THIS_MODULE,
0240 .attach = hp_sw_bus_attach,
0241 .detach = hp_sw_bus_detach,
0242 .activate = hp_sw_activate,
0243 .prep_fn = hp_sw_prep_fn,
0244 };
0245
0246 static int __init hp_sw_init(void)
0247 {
0248 return scsi_register_device_handler(&hp_sw_dh);
0249 }
0250
0251 static void __exit hp_sw_exit(void)
0252 {
0253 scsi_unregister_device_handler(&hp_sw_dh);
0254 }
0255
0256 module_init(hp_sw_init);
0257 module_exit(hp_sw_exit);
0258
0259 MODULE_DESCRIPTION("HP Active/Passive driver");
0260 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu");
0261 MODULE_LICENSE("GPL");