Fix simplex adapters with libata
[powerpc.git] / drivers / scsi / scsi_debug.c
index 9c0f358..3e2930b 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/module.h>
 
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
 #include <linux/types.h>
 #include "scsi_logging.h"
 #include "scsi_debug.h"
 
-#define SCSI_DEBUG_VERSION "1.80"
-static const char * scsi_debug_version_date = "20060914";
+#define SCSI_DEBUG_VERSION "1.81"
+static const char * scsi_debug_version_date = "20070104";
 
-/* Additional Sense Code (ASC) used */
+/* Additional Sense Code (ASC) */
 #define NO_ADDITIONAL_SENSE 0x0
 #define LOGICAL_UNIT_NOT_READY 0x4
 #define UNRECOVERED_READ_ERR 0x11
@@ -65,9 +64,13 @@ static const char * scsi_debug_version_date = "20060914";
 #define INVALID_FIELD_IN_PARAM_LIST 0x26
 #define POWERON_RESET 0x29
 #define SAVING_PARAMS_UNSUP 0x39
+#define TRANSPORT_PROBLEM 0x4b
 #define THRESHOLD_EXCEEDED 0x5d
 #define LOW_POWER_COND_ON 0x5e
 
+/* Additional Sense Code Qualifier (ASCQ) */
+#define ACK_NAK_TO 0x3
+
 #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
 
 /* Default values for driver parameters */
@@ -95,15 +98,20 @@ static const char * scsi_debug_version_date = "20060914";
 #define SCSI_DEBUG_OPT_MEDIUM_ERR   2
 #define SCSI_DEBUG_OPT_TIMEOUT   4
 #define SCSI_DEBUG_OPT_RECOVERED_ERR   8
+#define SCSI_DEBUG_OPT_TRANSPORT_ERR   16
 /* When "every_nth" > 0 then modulo "every_nth" commands:
  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
  *   - a RECOVERED_ERROR is simulated on successful read and write
  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ *   - a TRANSPORT_ERROR is simulated on successful read and write
+ *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
  *
  * When "every_nth" < 0 then after "- every_nth" commands:
  *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
  *   - a RECOVERED_ERROR is simulated on successful read and write
  *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ *   - a TRANSPORT_ERROR is simulated on successful read and write
+ *     commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set.
  * This will continue until some other action occurs (e.g. the user
  * writing a new value (other than -1 or 1) to every_nth via sysfs).
  */
@@ -254,6 +262,8 @@ static int resp_requests(struct scsi_cmnd * SCpnt,
                         struct sdebug_dev_info * devip);
 static int resp_start_stop(struct scsi_cmnd * scp,
                           struct sdebug_dev_info * devip);
+static int resp_report_tgtpgs(struct scsi_cmnd * scp,
+                             struct sdebug_dev_info * devip);
 static int resp_readcap(struct scsi_cmnd * SCpnt,
                        struct sdebug_dev_info * devip);
 static int resp_readcap16(struct scsi_cmnd * SCpnt,
@@ -287,9 +297,9 @@ static void __init sdebug_build_parts(unsigned char * ramp);
 static void __init init_all_queued(void);
 static void stop_all_queued(void);
 static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
-                          int dev_id_num, const char * dev_id_str,
-                          int dev_id_str_len);
+static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
+                          int target_dev_id, int dev_id_num,
+                          const char * dev_id_str, int dev_id_str_len);
 static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
 static int do_create_driverfs_files(void);
 static void do_remove_driverfs_files(void);
@@ -313,6 +323,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
        int target = SCpnt->device->id;
        struct sdebug_dev_info * devip = NULL;
        int inj_recovered = 0;
+       int inj_transport = 0;
        int delay_override = 0;
 
        if (done == NULL)
@@ -350,6 +361,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                        return 0; /* ignore command causing timeout */
                else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
                        inj_recovered = 1; /* to reads and writes below */
+               else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
+                       inj_transport = 1; /* to reads and writes below */
         }
 
        if (devip->wlun) {
@@ -422,6 +435,15 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                }
                errsts = resp_readcap16(SCpnt, devip);
                break;
+       case MAINTENANCE_IN:
+               if (MI_REPORT_TARGET_PGS != cmd[1]) {
+                       mk_sense_buffer(devip, ILLEGAL_REQUEST,
+                                       INVALID_OPCODE, 0);
+                       errsts = check_condition_result;
+                       break;
+               }
+               errsts = resp_report_tgtpgs(SCpnt, devip);
+               break;
        case READ_16:
        case READ_12:
        case READ_10:
@@ -457,7 +479,11 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                        mk_sense_buffer(devip, RECOVERED_ERROR,
                                        THRESHOLD_EXCEEDED, 0);
                        errsts = check_condition_result;
-               }
+               } else if (inj_transport && (0 == errsts)) {
+                        mk_sense_buffer(devip, ABORTED_COMMAND,
+                                        TRANSPORT_PROBLEM, ACK_NAK_TO);
+                        errsts = check_condition_result;
+                }
                break;
        case REPORT_LUNS:       /* mandatory, ignore unit attention */
                delay_override = 1;
@@ -520,6 +546,9 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
                delay_override = 1;
                errsts = check_readiness(SCpnt, 0, devip);
                break;
+       case WRITE_BUFFER:
+               errsts = check_readiness(SCpnt, 1, devip);
+               break;
        default:
                if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
                        printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
@@ -665,8 +694,9 @@ static const char * inq_vendor_id = "Linux   ";
 static const char * inq_product_id = "scsi_debug      ";
 static const char * inq_product_rev = "0004";
 
-static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
-                          int dev_id_num, const char * dev_id_str,
+static int inquiry_evpd_83(unsigned char * arr, int port_group_id,
+                          int target_dev_id, int dev_id_num,
+                          const char * dev_id_str,
                           int dev_id_str_len)
 {
        int num, port_a;
@@ -720,6 +750,15 @@ static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
        arr[num++] = (port_a >> 16) & 0xff;
        arr[num++] = (port_a >> 8) & 0xff;
        arr[num++] = port_a & 0xff;
+       /* NAA-5, Target port group identifier */
+       arr[num++] = 0x61;      /* proto=sas, binary */
+       arr[num++] = 0x95;      /* piv=1, target port group id */
+       arr[num++] = 0x0;
+       arr[num++] = 0x4;
+       arr[num++] = 0;
+       arr[num++] = 0;
+       arr[num++] = (port_group_id >> 8) & 0xff;
+       arr[num++] = port_group_id & 0xff;
        /* NAA-5, Target device identifier */
        arr[num++] = 0x61;      /* proto=sas, binary */
        arr[num++] = 0xa3;      /* piv=1, target device, naa */
@@ -928,12 +967,14 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                        struct sdebug_dev_info * devip)
 {
        unsigned char pq_pdt;
-       unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+       unsigned char * arr;
        unsigned char *cmd = (unsigned char *)scp->cmnd;
-       int alloc_len, n;
+       int alloc_len, n, ret;
 
        alloc_len = (cmd[3] << 8) + cmd[4];
-       memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+       arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
+       if (! arr)
+               return DID_REQUEUE << 16;
        if (devip->wlun)
                pq_pdt = 0x1e;  /* present, wlun */
        else if (scsi_debug_no_lun_0 && (0 == devip->lun))
@@ -944,12 +985,15 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
        if (0x2 & cmd[1]) {  /* CMDDT bit set */
                mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
                                0);
+               kfree(arr);
                return check_condition_result;
        } else if (0x1 & cmd[1]) {  /* EVPD bit set */
-               int lu_id_num, target_dev_id, len;
+               int lu_id_num, port_group_id, target_dev_id, len;
                char lu_id_str[6];
                int host_no = devip->sdbg_host->shost->host_no;
                
+               port_group_id = (((host_no + 1) & 0x7f) << 8) +
+                   (devip->channel & 0x7f);
                if (0 == scsi_debug_vpd_use_hostno)
                        host_no = 0;
                lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
@@ -977,8 +1021,9 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                        memcpy(&arr[4], lu_id_str, len);
                } else if (0x83 == cmd[2]) { /* device identification */
                        arr[1] = cmd[2];        /*sanity */
-                       arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
-                                                lu_id_num, lu_id_str, len);
+                       arr[3] = inquiry_evpd_83(&arr[4], port_group_id,
+                                                target_dev_id, lu_id_num,
+                                                lu_id_str, len);
                } else if (0x84 == cmd[2]) { /* Software interface ident. */
                        arr[1] = cmd[2];        /*sanity */
                        arr[3] = inquiry_evpd_84(&arr[4]);
@@ -1012,17 +1057,22 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                        /* Illegal request, invalid field in cdb */
                        mk_sense_buffer(devip, ILLEGAL_REQUEST,
                                        INVALID_FIELD_IN_CDB, 0);
+                       kfree(arr);
                        return check_condition_result;
                }
                len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
-               return fill_from_dev_buffer(scp, arr,
+               ret = fill_from_dev_buffer(scp, arr,
                            min(len, SDEBUG_MAX_INQ_ARR_SZ));
+               kfree(arr);
+               return ret;
        }
        /* drops through here for a standard inquiry */
        arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;     /* Removable disk */
        arr[2] = scsi_debug_scsi_level;
        arr[3] = 2;    /* response_data_format==2 */
        arr[4] = SDEBUG_LONG_INQ_SZ - 5;
+       if (0 == scsi_debug_vpd_use_hostno)
+               arr[5] = 0x10; /* claim: implicit TGPS */
        arr[6] = 0x10; /* claim: MultiP */
        /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
        arr[7] = 0xa; /* claim: LINKED + CMDQUE */
@@ -1039,8 +1089,10 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
                arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
        }
        arr[n++] = 0xc; arr[n++] = 0xf;  /* SAS-1.1 rev 10 */
-       return fill_from_dev_buffer(scp, arr,
+       ret = fill_from_dev_buffer(scp, arr,
                            min(alloc_len, SDEBUG_LONG_INQ_SZ));
+       kfree(arr);
+       return ret;
 }
 
 static int resp_requests(struct scsi_cmnd * scp,
@@ -1171,6 +1223,89 @@ static int resp_readcap16(struct scsi_cmnd * scp,
                                    min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
 }
 
+#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
+
+static int resp_report_tgtpgs(struct scsi_cmnd * scp,
+                             struct sdebug_dev_info * devip)
+{
+       unsigned char *cmd = (unsigned char *)scp->cmnd;
+       unsigned char * arr;
+       int host_no = devip->sdbg_host->shost->host_no;
+       int n, ret, alen, rlen;
+       int port_group_a, port_group_b, port_a, port_b;
+
+       alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8)
+               + cmd[9]);
+
+       arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
+       if (! arr)
+               return DID_REQUEUE << 16;
+       /*
+        * EVPD page 0x88 states we have two ports, one
+        * real and a fake port with no device connected.
+        * So we create two port groups with one port each
+        * and set the group with port B to unavailable.
+        */
+       port_a = 0x1; /* relative port A */
+       port_b = 0x2; /* relative port B */
+       port_group_a = (((host_no + 1) & 0x7f) << 8) +
+           (devip->channel & 0x7f);
+       port_group_b = (((host_no + 1) & 0x7f) << 8) +
+           (devip->channel & 0x7f) + 0x80;
+
+       /*
+        * The asymmetric access state is cycled according to the host_id.
+        */
+       n = 4;
+       if (0 == scsi_debug_vpd_use_hostno) {
+           arr[n++] = host_no % 3; /* Asymm access state */
+           arr[n++] = 0x0F; /* claim: all states are supported */
+       } else {
+           arr[n++] = 0x0; /* Active/Optimized path */
+           arr[n++] = 0x01; /* claim: only support active/optimized paths */
+       }
+       arr[n++] = (port_group_a >> 8) & 0xff;
+       arr[n++] = port_group_a & 0xff;
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = 0;    /* Status code */
+       arr[n++] = 0;    /* Vendor unique */
+       arr[n++] = 0x1;  /* One port per group */
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = (port_a >> 8) & 0xff;
+       arr[n++] = port_a & 0xff;
+       arr[n++] = 3;    /* Port unavailable */
+       arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
+       arr[n++] = (port_group_b >> 8) & 0xff;
+       arr[n++] = port_group_b & 0xff;
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = 0;    /* Status code */
+       arr[n++] = 0;    /* Vendor unique */
+       arr[n++] = 0x1;  /* One port per group */
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = 0;    /* Reserved */
+       arr[n++] = (port_b >> 8) & 0xff;
+       arr[n++] = port_b & 0xff;
+
+       rlen = n - 4;
+       arr[0] = (rlen >> 24) & 0xff;
+       arr[1] = (rlen >> 16) & 0xff;
+       arr[2] = (rlen >> 8) & 0xff;
+       arr[3] = rlen & 0xff;
+
+       /*
+        * Return the smallest value of either
+        * - The allocated length
+        * - The constructed command length
+        * - The maximum array size
+        */
+       rlen = min(alen,n);
+       ret = fill_from_dev_buffer(scp, arr,
+                                  min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
+       kfree(arr);
+       return ret;
+}
+
 /* <<Following mode page info copied from ST318451LW>> */
 
 static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
@@ -1883,6 +2018,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
        if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
                sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
        devip = devInfoReg(sdp);
+       if (NULL == devip)
+               return 1;       /* no resources, will be marked offline */
        sdp->hostdata = devip;
        if (sdp->host->cmd_per_lun)
                scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
@@ -1931,7 +2068,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
                }
        }
        if (NULL == open_devip) { /* try and make a new one */
-               open_devip = kzalloc(sizeof(*open_devip),GFP_KERNEL);
+               open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC);
                if (NULL == open_devip) {
                        printk(KERN_ERR "%s: out of memory at line %d\n",
                                __FUNCTION__, __LINE__);
@@ -2275,7 +2412,7 @@ MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
 MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
 MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
 MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
-MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
+MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
 MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
 MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
 MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
@@ -2830,7 +2967,6 @@ static int sdebug_add_adapter(void)
         struct list_head *lh, *lh_sf;
 
         sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
-
         if (NULL == sdbg_host) {
                 printk(KERN_ERR "%s: out of memory at line %d\n",
                        __FUNCTION__, __LINE__);