Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Target driver for EMC CLARiiON AX/CX-series hardware.
0004  * Based on code from Lars Marowsky-Bree <lmb@suse.de>
0005  * and Ed Goggin <egoggin@emc.com>.
0006  *
0007  * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
0008  * Copyright (C) 2006 Mike Christie
0009  */
0010 #include <linux/slab.h>
0011 #include <linux/module.h>
0012 #include <scsi/scsi.h>
0013 #include <scsi/scsi_eh.h>
0014 #include <scsi/scsi_dh.h>
0015 #include <scsi/scsi_device.h>
0016 
0017 #define CLARIION_NAME           "emc"
0018 
0019 #define CLARIION_TRESPASS_PAGE      0x22
0020 #define CLARIION_BUFFER_SIZE        0xFC
0021 #define CLARIION_TIMEOUT        (60 * HZ)
0022 #define CLARIION_RETRIES        3
0023 #define CLARIION_UNBOUND_LU     -1
0024 #define CLARIION_SP_A           0
0025 #define CLARIION_SP_B           1
0026 
0027 /* Flags */
0028 #define CLARIION_SHORT_TRESPASS     1
0029 #define CLARIION_HONOR_RESERVATIONS 2
0030 
0031 /* LUN states */
0032 #define CLARIION_LUN_UNINITIALIZED  -1
0033 #define CLARIION_LUN_UNBOUND        0
0034 #define CLARIION_LUN_BOUND      1
0035 #define CLARIION_LUN_OWNED      2
0036 
0037 static unsigned char long_trespass[] = {
0038     0, 0, 0, 0, 0, 0, 0, 0,
0039     CLARIION_TRESPASS_PAGE, /* Page code */
0040     0x09,           /* Page length - 2 */
0041     0x01,           /* Trespass code */
0042     0xff, 0xff,     /* Trespass target */
0043     0, 0, 0, 0, 0, 0    /* Reserved bytes / unknown */
0044 };
0045 
0046 static unsigned char short_trespass[] = {
0047     0, 0, 0, 0,
0048     CLARIION_TRESPASS_PAGE, /* Page code */
0049     0x02,           /* Page length - 2 */
0050     0x01,           /* Trespass code */
0051     0xff,           /* Trespass target */
0052 };
0053 
0054 static const char * lun_state[] =
0055 {
0056     "not bound",
0057     "bound",
0058     "owned",
0059 };
0060 
0061 struct clariion_dh_data {
0062     /*
0063      * Flags:
0064      *  CLARIION_SHORT_TRESPASS
0065      * Use short trespass command (FC-series) or the long version
0066      * (default for AX/CX CLARiiON arrays).
0067      *
0068      *  CLARIION_HONOR_RESERVATIONS
0069      * Whether or not (default) to honor SCSI reservations when
0070      * initiating a switch-over.
0071      */
0072     unsigned flags;
0073     /*
0074      * I/O buffer for both MODE_SELECT and INQUIRY commands.
0075      */
0076     unsigned char buffer[CLARIION_BUFFER_SIZE];
0077     /*
0078      * LUN state
0079      */
0080     int lun_state;
0081     /*
0082      * SP Port number
0083      */
0084     int port;
0085     /*
0086      * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this
0087      * path's mapped LUN
0088      */
0089     int default_sp;
0090     /*
0091      * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this
0092      * path's mapped LUN
0093      */
0094     int current_sp;
0095 };
0096 
0097 /*
0098  * Parse MODE_SELECT cmd reply.
0099  */
0100 static int trespass_endio(struct scsi_device *sdev,
0101               struct scsi_sense_hdr *sshdr)
0102 {
0103     int err = SCSI_DH_IO;
0104 
0105     sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, "
0106             "0x%2x, 0x%2x while sending CLARiiON trespass "
0107             "command.\n", CLARIION_NAME, sshdr->sense_key,
0108             sshdr->asc, sshdr->ascq);
0109 
0110     if (sshdr->sense_key == 0x05 && sshdr->asc == 0x04 &&
0111         sshdr->ascq == 0x00) {
0112         /*
0113          * Array based copy in progress -- do not send
0114          * mode_select or copy will be aborted mid-stream.
0115          */
0116         sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in "
0117                 "progress while sending CLARiiON trespass "
0118                 "command.\n", CLARIION_NAME);
0119         err = SCSI_DH_DEV_TEMP_BUSY;
0120     } else if (sshdr->sense_key == 0x02 && sshdr->asc == 0x04 &&
0121            sshdr->ascq == 0x03) {
0122         /*
0123          * LUN Not Ready - Manual Intervention Required
0124          * indicates in-progress ucode upgrade (NDU).
0125          */
0126         sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress "
0127                 "ucode upgrade NDU operation while sending "
0128                 "CLARiiON trespass command.\n", CLARIION_NAME);
0129         err = SCSI_DH_DEV_TEMP_BUSY;
0130     } else
0131         err = SCSI_DH_DEV_FAILED;
0132     return err;
0133 }
0134 
0135 static int parse_sp_info_reply(struct scsi_device *sdev,
0136                    struct clariion_dh_data *csdev)
0137 {
0138     int err = SCSI_DH_OK;
0139 
0140     /* check for in-progress ucode upgrade (NDU) */
0141     if (csdev->buffer[48] != 0) {
0142         sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress "
0143                 "ucode upgrade NDU operation while finding "
0144                 "current active SP.", CLARIION_NAME);
0145         err = SCSI_DH_DEV_TEMP_BUSY;
0146         goto out;
0147     }
0148     if (csdev->buffer[4] > 2) {
0149         /* Invalid buffer format */
0150         sdev_printk(KERN_NOTICE, sdev,
0151                 "%s: invalid VPD page 0xC0 format\n",
0152                 CLARIION_NAME);
0153         err = SCSI_DH_NOSYS;
0154         goto out;
0155     }
0156     switch (csdev->buffer[28] & 0x0f) {
0157     case 6:
0158         sdev_printk(KERN_NOTICE, sdev,
0159                 "%s: ALUA failover mode detected\n",
0160                 CLARIION_NAME);
0161         break;
0162     case 4:
0163         /* Linux failover */
0164         break;
0165     default:
0166         sdev_printk(KERN_WARNING, sdev,
0167                 "%s: Invalid failover mode %d\n",
0168                 CLARIION_NAME, csdev->buffer[28] & 0x0f);
0169         err = SCSI_DH_NOSYS;
0170         goto out;
0171     }
0172 
0173     csdev->default_sp = csdev->buffer[5];
0174     csdev->lun_state = csdev->buffer[4];
0175     csdev->current_sp = csdev->buffer[8];
0176     csdev->port = csdev->buffer[7];
0177     if (csdev->lun_state == CLARIION_LUN_OWNED)
0178         sdev->access_state = SCSI_ACCESS_STATE_OPTIMAL;
0179     else
0180         sdev->access_state = SCSI_ACCESS_STATE_STANDBY;
0181     if (csdev->default_sp == csdev->current_sp)
0182         sdev->access_state |= SCSI_ACCESS_STATE_PREFERRED;
0183 out:
0184     return err;
0185 }
0186 
0187 #define emc_default_str "FC (Legacy)"
0188 
0189 static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer)
0190 {
0191     unsigned char len = buffer[4] + 5;
0192     char *sp_model = NULL;
0193     unsigned char sp_len, serial_len;
0194 
0195     if (len < 160) {
0196         sdev_printk(KERN_WARNING, sdev,
0197                 "%s: Invalid information section length %d\n",
0198                 CLARIION_NAME, len);
0199         /* Check for old FC arrays */
0200         if (!strncmp(buffer + 8, "DGC", 3)) {
0201             /* Old FC array, not supporting extended information */
0202             sp_model = emc_default_str;
0203         }
0204         goto out;
0205     }
0206 
0207     /*
0208      * Parse extended information for SP model number
0209      */
0210     serial_len = buffer[160];
0211     if (serial_len == 0 || serial_len + 161 > len) {
0212         sdev_printk(KERN_WARNING, sdev,
0213                 "%s: Invalid array serial number length %d\n",
0214                 CLARIION_NAME, serial_len);
0215         goto out;
0216     }
0217     sp_len = buffer[99];
0218     if (sp_len == 0 || serial_len + sp_len + 161 > len) {
0219         sdev_printk(KERN_WARNING, sdev,
0220                 "%s: Invalid model number length %d\n",
0221                 CLARIION_NAME, sp_len);
0222         goto out;
0223     }
0224     sp_model = &buffer[serial_len + 161];
0225     /* Strip whitespace at the end */
0226     while (sp_len > 1 && sp_model[sp_len - 1] == ' ')
0227         sp_len--;
0228 
0229     sp_model[sp_len] = '\0';
0230 
0231 out:
0232     return sp_model;
0233 }
0234 
0235 static int send_trespass_cmd(struct scsi_device *sdev,
0236                 struct clariion_dh_data *csdev)
0237 {
0238     unsigned char *page22;
0239     unsigned char cdb[MAX_COMMAND_SIZE];
0240     int err, res = SCSI_DH_OK, len;
0241     struct scsi_sense_hdr sshdr;
0242     blk_opf_t req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT |
0243         REQ_FAILFAST_DRIVER;
0244 
0245     if (csdev->flags & CLARIION_SHORT_TRESPASS) {
0246         page22 = short_trespass;
0247         if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
0248             /* Set Honor Reservations bit */
0249             page22[6] |= 0x80;
0250         len = sizeof(short_trespass);
0251         cdb[0] = MODE_SELECT;
0252         cdb[1] = 0x10;
0253         cdb[4] = len;
0254     } else {
0255         page22 = long_trespass;
0256         if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS))
0257             /* Set Honor Reservations bit */
0258             page22[10] |= 0x80;
0259         len = sizeof(long_trespass);
0260         cdb[0] = MODE_SELECT_10;
0261         cdb[8] = len;
0262     }
0263     BUG_ON((len > CLARIION_BUFFER_SIZE));
0264     memcpy(csdev->buffer, page22, len);
0265 
0266     err = scsi_execute(sdev, cdb, DMA_TO_DEVICE, csdev->buffer, len, NULL,
0267             &sshdr, CLARIION_TIMEOUT * HZ, CLARIION_RETRIES,
0268             req_flags, 0, NULL);
0269     if (err) {
0270         if (scsi_sense_valid(&sshdr))
0271             res = trespass_endio(sdev, &sshdr);
0272         else {
0273             sdev_printk(KERN_INFO, sdev,
0274                     "%s: failed to send MODE SELECT: %x\n",
0275                     CLARIION_NAME, err);
0276             res = SCSI_DH_IO;
0277         }
0278     }
0279 
0280     return res;
0281 }
0282 
0283 static enum scsi_disposition clariion_check_sense(struct scsi_device *sdev,
0284                     struct scsi_sense_hdr *sense_hdr)
0285 {
0286     switch (sense_hdr->sense_key) {
0287     case NOT_READY:
0288         if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03)
0289             /*
0290              * LUN Not Ready - Manual Intervention Required
0291              * indicates this is a passive path.
0292              *
0293              * FIXME: However, if this is seen and EVPD C0
0294              * indicates that this is due to a NDU in
0295              * progress, we should set FAIL_PATH too.
0296              * This indicates we might have to do a SCSI
0297              * inquiry in the end_io path. Ugh.
0298              *
0299              * Can return FAILED only when we want the error
0300              * recovery process to kick in.
0301              */
0302             return SUCCESS;
0303         break;
0304     case ILLEGAL_REQUEST:
0305         if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01)
0306             /*
0307              * An array based copy is in progress. Do not
0308              * fail the path, do not bypass to another PG,
0309              * do not retry. Fail the IO immediately.
0310              * (Actually this is the same conclusion as in
0311              * the default handler, but lets make sure.)
0312              *
0313              * Can return FAILED only when we want the error
0314              * recovery process to kick in.
0315              */
0316             return SUCCESS;
0317         break;
0318     case UNIT_ATTENTION:
0319         if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00)
0320             /*
0321              * Unit Attention Code. This is the first IO
0322              * to the new path, so just retry.
0323              */
0324             return ADD_TO_MLQUEUE;
0325         break;
0326     }
0327 
0328     return SCSI_RETURN_NOT_HANDLED;
0329 }
0330 
0331 static blk_status_t clariion_prep_fn(struct scsi_device *sdev,
0332         struct request *req)
0333 {
0334     struct clariion_dh_data *h = sdev->handler_data;
0335 
0336     if (h->lun_state != CLARIION_LUN_OWNED) {
0337         req->rq_flags |= RQF_QUIET;
0338         return BLK_STS_IOERR;
0339     }
0340 
0341     return BLK_STS_OK;
0342 }
0343 
0344 static int clariion_std_inquiry(struct scsi_device *sdev,
0345                 struct clariion_dh_data *csdev)
0346 {
0347     int err = SCSI_DH_OK;
0348     char *sp_model;
0349 
0350     sp_model = parse_sp_model(sdev, sdev->inquiry);
0351     if (!sp_model) {
0352         err = SCSI_DH_DEV_UNSUPP;
0353         goto out;
0354     }
0355 
0356     /*
0357      * FC Series arrays do not support long trespass
0358      */
0359     if (!strlen(sp_model) || !strncmp(sp_model, "FC",2))
0360         csdev->flags |= CLARIION_SHORT_TRESPASS;
0361 
0362     sdev_printk(KERN_INFO, sdev,
0363             "%s: detected Clariion %s, flags %x\n",
0364             CLARIION_NAME, sp_model, csdev->flags);
0365 out:
0366     return err;
0367 }
0368 
0369 static int clariion_send_inquiry(struct scsi_device *sdev,
0370                  struct clariion_dh_data *csdev)
0371 {
0372     int err = SCSI_DH_IO;
0373 
0374     if (!scsi_get_vpd_page(sdev, 0xC0, csdev->buffer,
0375                    CLARIION_BUFFER_SIZE))
0376         err = parse_sp_info_reply(sdev, csdev);
0377 
0378     return err;
0379 }
0380 
0381 static int clariion_activate(struct scsi_device *sdev,
0382                 activate_complete fn, void *data)
0383 {
0384     struct clariion_dh_data *csdev = sdev->handler_data;
0385     int result;
0386 
0387     result = clariion_send_inquiry(sdev, csdev);
0388     if (result != SCSI_DH_OK)
0389         goto done;
0390 
0391     if (csdev->lun_state == CLARIION_LUN_OWNED)
0392         goto done;
0393 
0394     result = send_trespass_cmd(sdev, csdev);
0395     if (result != SCSI_DH_OK)
0396         goto done;
0397     sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n",
0398             CLARIION_NAME,
0399             csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" );
0400 
0401     /* Update status */
0402     result = clariion_send_inquiry(sdev, csdev);
0403     if (result != SCSI_DH_OK)
0404         goto done;
0405 
0406 done:
0407     sdev_printk(KERN_INFO, sdev,
0408             "%s: at SP %c Port %d (%s, default SP %c)\n",
0409             CLARIION_NAME, csdev->current_sp + 'A',
0410             csdev->port, lun_state[csdev->lun_state],
0411             csdev->default_sp + 'A');
0412 
0413     if (fn)
0414         fn(data, result);
0415     return 0;
0416 }
0417 /*
0418  * params - parameters in the following format
0419  *      "no_of_params\0param1\0param2\0param3\0...\0"
0420  *      for example, string for 2 parameters with value 10 and 21
0421  *      is specified as "2\010\021\0".
0422  */
0423 static int clariion_set_params(struct scsi_device *sdev, const char *params)
0424 {
0425     struct clariion_dh_data *csdev = sdev->handler_data;
0426     unsigned int hr = 0, st = 0, argc;
0427     const char *p = params;
0428     int result = SCSI_DH_OK;
0429 
0430     if ((sscanf(params, "%u", &argc) != 1) || (argc != 2))
0431         return -EINVAL;
0432 
0433     while (*p++)
0434         ;
0435     if ((sscanf(p, "%u", &st) != 1) || (st > 1))
0436         return -EINVAL;
0437 
0438     while (*p++)
0439         ;
0440     if ((sscanf(p, "%u", &hr) != 1) || (hr > 1))
0441         return -EINVAL;
0442 
0443     if (st)
0444         csdev->flags |= CLARIION_SHORT_TRESPASS;
0445     else
0446         csdev->flags &= ~CLARIION_SHORT_TRESPASS;
0447 
0448     if (hr)
0449         csdev->flags |= CLARIION_HONOR_RESERVATIONS;
0450     else
0451         csdev->flags &= ~CLARIION_HONOR_RESERVATIONS;
0452 
0453     /*
0454      * If this path is owned, we have to send a trespass command
0455      * with the new parameters. If not, simply return. Next trespass
0456      * command would use the parameters.
0457      */
0458     if (csdev->lun_state != CLARIION_LUN_OWNED)
0459         goto done;
0460 
0461     csdev->lun_state = CLARIION_LUN_UNINITIALIZED;
0462     result = send_trespass_cmd(sdev, csdev);
0463     if (result != SCSI_DH_OK)
0464         goto done;
0465 
0466     /* Update status */
0467     result = clariion_send_inquiry(sdev, csdev);
0468 
0469 done:
0470     return result;
0471 }
0472 
0473 static int clariion_bus_attach(struct scsi_device *sdev)
0474 {
0475     struct clariion_dh_data *h;
0476     int err;
0477 
0478     h = kzalloc(sizeof(*h) , GFP_KERNEL);
0479     if (!h)
0480         return SCSI_DH_NOMEM;
0481     h->lun_state = CLARIION_LUN_UNINITIALIZED;
0482     h->default_sp = CLARIION_UNBOUND_LU;
0483     h->current_sp = CLARIION_UNBOUND_LU;
0484 
0485     err = clariion_std_inquiry(sdev, h);
0486     if (err != SCSI_DH_OK)
0487         goto failed;
0488 
0489     err = clariion_send_inquiry(sdev, h);
0490     if (err != SCSI_DH_OK)
0491         goto failed;
0492 
0493     sdev_printk(KERN_INFO, sdev,
0494             "%s: connected to SP %c Port %d (%s, default SP %c)\n",
0495             CLARIION_NAME, h->current_sp + 'A',
0496             h->port, lun_state[h->lun_state],
0497             h->default_sp + 'A');
0498 
0499     sdev->handler_data = h;
0500     return SCSI_DH_OK;
0501 
0502 failed:
0503     kfree(h);
0504     return err;
0505 }
0506 
0507 static void clariion_bus_detach(struct scsi_device *sdev)
0508 {
0509     kfree(sdev->handler_data);
0510     sdev->handler_data = NULL;
0511 }
0512 
0513 static struct scsi_device_handler clariion_dh = {
0514     .name       = CLARIION_NAME,
0515     .module     = THIS_MODULE,
0516     .attach     = clariion_bus_attach,
0517     .detach     = clariion_bus_detach,
0518     .check_sense    = clariion_check_sense,
0519     .activate   = clariion_activate,
0520     .prep_fn    = clariion_prep_fn,
0521     .set_params = clariion_set_params,
0522 };
0523 
0524 static int __init clariion_init(void)
0525 {
0526     int r;
0527 
0528     r = scsi_register_device_handler(&clariion_dh);
0529     if (r != 0)
0530         printk(KERN_ERR "%s: Failed to register scsi device handler.",
0531             CLARIION_NAME);
0532     return r;
0533 }
0534 
0535 static void __exit clariion_exit(void)
0536 {
0537     scsi_unregister_device_handler(&clariion_dh);
0538 }
0539 
0540 module_init(clariion_init);
0541 module_exit(clariion_exit);
0542 
0543 MODULE_DESCRIPTION("EMC CX/AX/FC-family driver");
0544 MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, Chandra Seetharaman <sekharan@us.ibm.com>");
0545 MODULE_LICENSE("GPL");