win-pvdrivers

changeset 496:785de85f3db7

Added support for >2TB block devices
author James Harper <james.harper@bendigoit.com.au>
date Wed Dec 17 20:09:32 2008 +1100 (2008-12-17)
parents a6e3f76419c3
children 312a41f82b8f
files xenvbd/xenvbd.c
line diff
     1.1 --- a/xenvbd/xenvbd.c	Mon Dec 15 19:17:13 2008 +1100
     1.2 +++ b/xenvbd/xenvbd.c	Wed Dec 17 20:09:32 2008 +1100
     1.3 @@ -43,6 +43,17 @@ DRIVER_INITIALIZE DriverEntry;
     1.4  
     1.5  static BOOLEAN dump_mode = FALSE;
     1.6  
     1.7 +ULONGLONG parse_numeric_string(PCHAR string)
     1.8 +{
     1.9 +  ULONGLONG val = 0;
    1.10 +  while (*string != 0)
    1.11 +  {
    1.12 +    val = val * 10 + (*string - '0');
    1.13 +    string++;
    1.14 +  }
    1.15 +  return val;
    1.16 +}
    1.17 +
    1.18  static blkif_shadow_t *
    1.19  get_shadow_from_freelist(PXENVBD_DEVICE_DATA xvdd)
    1.20  {
    1.21 @@ -175,9 +186,9 @@ XenVbd_InitFromConfig(PXENVBD_DEVICE_DAT
    1.22      case XEN_INIT_TYPE_READ_STRING_FRONT:
    1.23        KdPrint((__DRIVER_NAME "     XEN_INIT_TYPE_READ_STRING - %s = %s\n", setting, value));
    1.24        if (strcmp(setting, "sectors") == 0)
    1.25 -        xvdd->total_sectors = atoi(value);
    1.26 +        xvdd->total_sectors = parse_numeric_string(value);
    1.27        else if (strcmp(setting, "sector-size") == 0)
    1.28 -        xvdd->bytes_per_sector = atoi(value);
    1.29 +        xvdd->bytes_per_sector = (ULONG)parse_numeric_string(value);
    1.30        else if (strcmp(setting, "device-type") == 0)
    1.31        {
    1.32          if (strcmp(value, "disk") == 0)
    1.33 @@ -340,6 +351,64 @@ XenVbd_DumpStats()
    1.34    KdPrint((__DRIVER_NAME "     stat_outstanding_requests = %d\n", stat_outstanding_requests));
    1.35  }
    1.36  
    1.37 +static __inline ULONG
    1.38 +decode_cdb_length(PSCSI_REQUEST_BLOCK srb)
    1.39 +{
    1.40 +  switch (srb->Cdb[0])
    1.41 +  {
    1.42 +  case SCSIOP_READ:
    1.43 +  case SCSIOP_WRITE:
    1.44 +    return (srb->Cdb[7] << 8) | srb->Cdb[8];
    1.45 +  case SCSIOP_READ16:
    1.46 +  case SCSIOP_WRITE16:
    1.47 +    return (srb->Cdb[10] << 24) | (srb->Cdb[11] << 16) | (srb->Cdb[12] << 8) | srb->Cdb[13];    
    1.48 +  default:
    1.49 +    return 0;
    1.50 +  }
    1.51 +}
    1.52 +
    1.53 +static __inline ULONGLONG
    1.54 +decode_cdb_sector(PSCSI_REQUEST_BLOCK srb)
    1.55 +{
    1.56 +  ULONGLONG sector;
    1.57 +  
    1.58 +  switch (srb->Cdb[0])
    1.59 +  {
    1.60 +  case SCSIOP_READ:
    1.61 +  case SCSIOP_WRITE:
    1.62 +    sector = (srb->Cdb[2] << 24) | (srb->Cdb[3] << 16) | (srb->Cdb[4] << 8) | srb->Cdb[5];
    1.63 +    break;
    1.64 +  case SCSIOP_READ16:
    1.65 +  case SCSIOP_WRITE16:
    1.66 +    sector = ((ULONGLONG)srb->Cdb[2] << 56) | ((ULONGLONG)srb->Cdb[3] << 48)
    1.67 +           | ((ULONGLONG)srb->Cdb[4] << 40) | ((ULONGLONG)srb->Cdb[5] << 32)
    1.68 +           | ((ULONGLONG)srb->Cdb[6] << 24) | ((ULONGLONG)srb->Cdb[7] << 16)
    1.69 +           | ((ULONGLONG)srb->Cdb[8] << 8) | ((ULONGLONG)srb->Cdb[9]);
    1.70 +    //KdPrint((__DRIVER_NAME "     sector_number = %d (high) %d (low)\n", (ULONG)(sector >> 32), (ULONG)sector));
    1.71 +    break;
    1.72 +  default:
    1.73 +    sector = 0;
    1.74 +    break;
    1.75 +  }
    1.76 +  return sector;
    1.77 +}
    1.78 +
    1.79 +static __inline BOOLEAN
    1.80 +decode_cdb_is_read(PSCSI_REQUEST_BLOCK srb)
    1.81 +{
    1.82 +  switch (srb->Cdb[0])
    1.83 +  {
    1.84 +  case SCSIOP_READ:
    1.85 +  case SCSIOP_READ16:
    1.86 +    return TRUE;
    1.87 +  case SCSIOP_WRITE:
    1.88 +  case SCSIOP_WRITE16:
    1.89 +    return FALSE;
    1.90 +  default:
    1.91 +    return FALSE;
    1.92 +  }
    1.93 +}
    1.94 +
    1.95  static VOID
    1.96  XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb, ULONG srb_offset)
    1.97  {
    1.98 @@ -354,7 +423,7 @@ XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA 
    1.99    //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   1.100  
   1.101    //ASSERT(!(srb_offset == 0 && xvdd->split_request_in_progress));
   1.102 -  block_count = (srb->Cdb[7] << 8) | srb->Cdb[8];
   1.103 +  block_count = decode_cdb_length(srb);;
   1.104    block_count *= xvdd->bytes_per_sector / 512;
   1.105    if (PtrToUlong(srb->DataBuffer) & 511) /* use SrbExtension intead of DataBuffer if DataBuffer is not aligned to sector size */
   1.106    {
   1.107 @@ -393,19 +462,19 @@ XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA 
   1.108        else
   1.109          stat_unaligned_gt_65536++;
   1.110      }
   1.111 -    if (srb->Cdb[0] == SCSIOP_WRITE)
   1.112 +    if (decode_cdb_is_read(srb))
   1.113 +      stat_reads++;
   1.114 +    else
   1.115        stat_writes++;
   1.116 -    else
   1.117 -      stat_reads++;
   1.118      stat_outstanding_requests++;
   1.119    }
   1.120    
   1.121    shadow = get_shadow_from_freelist(xvdd);
   1.122    ASSERT(shadow);
   1.123 -  shadow->req.sector_number = (srb->Cdb[2] << 24) | (srb->Cdb[3] << 16) | (srb->Cdb[4] << 8) | srb->Cdb[5];
   1.124 +  shadow->req.sector_number = decode_cdb_sector(srb);
   1.125    shadow->req.sector_number *= xvdd->bytes_per_sector / 512;
   1.126    shadow->req.handle = 0;
   1.127 -  shadow->req.operation = (srb->Cdb[0] == SCSIOP_READ)?BLKIF_OP_READ:BLKIF_OP_WRITE;
   1.128 +  shadow->req.operation = decode_cdb_is_read(srb)?BLKIF_OP_READ:BLKIF_OP_WRITE;
   1.129    shadow->req.nr_segments = 0;
   1.130    shadow->offset = srb_offset;
   1.131    shadow->length = transfer_length;
   1.132 @@ -419,7 +488,7 @@ XenVbd_PutSrbOnRing(PXENVBD_DEVICE_DATA 
   1.133    {
   1.134      shadow->req.sector_number += srb_offset / 512; //xvdd->bytes_per_sector;
   1.135      //KdPrint((__DRIVER_NAME "     Using unaligned buffer - DataBuffer = %p, SrbExtension = %p, total length = %d, offset = %d, length = %d, sector = %d\n", srb->DataBuffer, srb->SrbExtension, block_count * 512, shadow->offset, shadow->length, (ULONG)shadow->req.sector_number));
   1.136 -    if (srb->Cdb[0] == SCSIOP_WRITE)
   1.137 +    if (!decode_cdb_is_read(srb))
   1.138      {
   1.139        memcpy(ptr, ((PUCHAR)srb->DataBuffer) + srb_offset, shadow->length);
   1.140      }
   1.141 @@ -656,21 +725,44 @@ XenVbd_HwScsiInitialize(PVOID DeviceExte
   1.142  static ULONG
   1.143  XenVbd_FillModePage(PXENVBD_DEVICE_DATA xvdd, PSCSI_REQUEST_BLOCK srb)
   1.144  {
   1.145 -  PCDB cdb;
   1.146    PMODE_PARAMETER_HEADER parameter_header;
   1.147    PMODE_PARAMETER_BLOCK param_block;
   1.148    PMODE_FORMAT_PAGE format_page;
   1.149 -  UCHAR page_code;
   1.150    ULONG offset;
   1.151    UCHAR buffer[256];
   1.152    BOOLEAN valid_page = FALSE;
   1.153 +  BOOLEAN cdb_llbaa;
   1.154 +  BOOLEAN cdb_dbd;
   1.155 +  UCHAR cdb_page_code;
   1.156 +  USHORT cdb_allocation_length;
   1.157  
   1.158    UNREFERENCED_PARAMETER(xvdd);
   1.159  
   1.160    //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
   1.161    
   1.162 -  cdb = (PCDB)srb->Cdb;
   1.163 -  page_code = cdb->MODE_SENSE.PageCode;
   1.164 +  //cdb = (PCDB)srb->Cdb;
   1.165 +  switch (srb->Cdb[0])
   1.166 +  {
   1.167 +  case SCSIOP_MODE_SENSE:
   1.168 +    cdb_llbaa = FALSE;
   1.169 +    cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
   1.170 +    cdb_page_code = srb->Cdb[2] & 0x3f;
   1.171 +    cdb_allocation_length = srb->Cdb[4];
   1.172 +    KdPrint((__DRIVER_NAME "     SCSIOP_MODE_SENSE llbaa = %d, dbd = %d, page_code = %d, allocation_length = %d\n",
   1.173 +      cdb_llbaa, cdb_dbd, cdb_page_code, cdb_allocation_length));
   1.174 +    break;
   1.175 +  case SCSIOP_MODE_SENSE10:
   1.176 +    cdb_llbaa = (BOOLEAN)!!(srb->Cdb[1] & 16);
   1.177 +    cdb_dbd = (BOOLEAN)!!(srb->Cdb[1] & 8);
   1.178 +    cdb_page_code = srb->Cdb[2] & 0x3f;
   1.179 +    cdb_allocation_length = (srb->Cdb[7] << 8) | srb->Cdb[8];
   1.180 +    KdPrint((__DRIVER_NAME "     SCSIOP_MODE_SENSE10 llbaa = %d, dbd = %d, page_code = %d, allocation_length = %d\n",
   1.181 +      cdb_llbaa, cdb_dbd, cdb_page_code, cdb_allocation_length));
   1.182 +    break;
   1.183 +  default:
   1.184 +    KdPrint((__DRIVER_NAME "     SCSIOP_MODE_SENSE_WTF (%02x)\n", (ULONG)srb->Cdb[0]));
   1.185 +    return FALSE;
   1.186 +  }
   1.187    offset = 0;
   1.188    RtlZeroMemory(srb->DataBuffer, srb->DataTransferLength);
   1.189    RtlZeroMemory(buffer, ARRAY_SIZE(buffer));
   1.190 @@ -687,7 +779,7 @@ XenVbd_FillModePage(PXENVBD_DEVICE_DATA 
   1.191      parameter_header->DeviceSpecificParameter|=MODE_DSP_WRITE_PROTECT; 
   1.192    }
   1.193    
   1.194 -  if (!cdb->MODE_SENSE.Dbd)
   1.195 +  if (!cdb_dbd)
   1.196    {
   1.197      parameter_header->BlockDescriptorLength += sizeof(MODE_PARAMETER_BLOCK);
   1.198      param_block = (PMODE_PARAMETER_BLOCK)&buffer[offset];
   1.199 @@ -713,7 +805,7 @@ XenVbd_FillModePage(PXENVBD_DEVICE_DATA 
   1.200      }
   1.201      offset += sizeof(MODE_PARAMETER_BLOCK);
   1.202    }
   1.203 -  if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (page_code == MODE_PAGE_FORMAT_DEVICE || page_code == MODE_SENSE_RETURN_ALL))
   1.204 +  if (xvdd->device_type == XENVBD_DEVICETYPE_DISK && (cdb_page_code == MODE_PAGE_FORMAT_DEVICE || cdb_page_code == MODE_SENSE_RETURN_ALL))
   1.205    {
   1.206      valid_page = TRUE;
   1.207      format_page = (PMODE_FORMAT_PAGE)&buffer[offset];
   1.208 @@ -730,7 +822,7 @@ XenVbd_FillModePage(PXENVBD_DEVICE_DATA 
   1.209      offset += sizeof(MODE_FORMAT_PAGE);
   1.210    }
   1.211    parameter_header->ModeDataLength = (UCHAR)(offset - 1);
   1.212 -  if (!valid_page && page_code != MODE_SENSE_RETURN_ALL)
   1.213 +  if (!valid_page && cdb_page_code != MODE_SENSE_RETURN_ALL)
   1.214    {
   1.215      srb->SrbStatus = SRB_STATUS_ERROR;
   1.216    }
   1.217 @@ -866,14 +958,14 @@ XenVbd_HwScsiInterrupt(PVOID DeviceExten
   1.218          shadow = &xvdd->shadows[rep->id];
   1.219          srb = shadow->srb;
   1.220          ASSERT(srb != NULL);
   1.221 -        block_count = (srb->Cdb[7] << 8) | srb->Cdb[8];
   1.222 +        block_count = decode_cdb_length(srb);
   1.223          block_count *= xvdd->bytes_per_sector / 512;
   1.224          if (rep->status == BLKIF_RSP_OKAY)
   1.225            srb->SrbStatus = SRB_STATUS_SUCCESS;
   1.226          else
   1.227          {
   1.228            KdPrint((__DRIVER_NAME "     Xen Operation returned error\n"));
   1.229 -          if (srb->Cdb[0] == SCSIOP_READ)
   1.230 +          if (decode_cdb_is_read(srb))
   1.231              KdPrint((__DRIVER_NAME "     Operation = Read\n"));
   1.232            else
   1.233              KdPrint((__DRIVER_NAME "     Operation = Write\n"));
   1.234 @@ -898,11 +990,11 @@ XenVbd_HwScsiInterrupt(PVOID DeviceExten
   1.235  
   1.236          if (PtrToUlong(srb->DataBuffer) & 511) /* use SrbExtension intead of DataBuffer if DataBuffer is not aligned to sector size */
   1.237          {
   1.238 -          if (srb->Cdb[0] == SCSIOP_READ)
   1.239 +          if (decode_cdb_is_read(srb))
   1.240              memcpy(((PUCHAR)srb->DataBuffer) + shadow->offset, GET_PAGE_ALIGNED(srb->SrbExtension), shadow->length);
   1.241            offset = shadow->offset + shadow->length;
   1.242            put_shadow_on_freelist(xvdd, shadow);
   1.243 -          if (offset == block_count * 512)
   1.244 +          if (offset == (ULONG)block_count * 512)
   1.245            {
   1.246              ScsiPortNotification(RequestComplete, xvdd, srb);
   1.247              stat_outstanding_requests--;
   1.248 @@ -1140,12 +1232,37 @@ XenVbd_HwScsiStartIo(PVOID DeviceExtensi
   1.249        Srb->ScsiStatus = 0;
   1.250        Srb->SrbStatus = SRB_STATUS_SUCCESS;
   1.251        break;
   1.252 +    case SCSIOP_READ_CAPACITY16:
   1.253 +      //KdPrint((__DRIVER_NAME "     Command = READ_CAPACITY\n"));
   1.254 +      //KdPrint((__DRIVER_NAME "       LUN = %d, RelAdr = %d\n", Srb->Cdb[1] >> 4, Srb->Cdb[1] & 1));
   1.255 +      //KdPrint((__DRIVER_NAME "       LBA = %02x%02x%02x%02x\n", Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5]));
   1.256 +      //KdPrint((__DRIVER_NAME "       PMI = %d\n", Srb->Cdb[8] & 1));
   1.257 +      DataBuffer = Srb->DataBuffer;
   1.258 +      RtlZeroMemory(DataBuffer, Srb->DataTransferLength);
   1.259 +      DataBuffer[0] = (unsigned char)((xvdd->total_sectors - 1) >> 56) & 0xff;
   1.260 +      DataBuffer[1] = (unsigned char)((xvdd->total_sectors - 1) >> 48) & 0xff;
   1.261 +      DataBuffer[2] = (unsigned char)((xvdd->total_sectors - 1) >> 40) & 0xff;
   1.262 +      DataBuffer[3] = (unsigned char)((xvdd->total_sectors - 1) >> 32) & 0xff;
   1.263 +      DataBuffer[4] = (unsigned char)((xvdd->total_sectors - 1) >> 24) & 0xff;
   1.264 +      DataBuffer[5] = (unsigned char)((xvdd->total_sectors - 1) >> 16) & 0xff;
   1.265 +      DataBuffer[6] = (unsigned char)((xvdd->total_sectors - 1) >> 8) & 0xff;
   1.266 +      DataBuffer[7] = (unsigned char)((xvdd->total_sectors - 1) >> 0) & 0xff;
   1.267 +      DataBuffer[8] = (unsigned char)(xvdd->bytes_per_sector >> 24) & 0xff;
   1.268 +      DataBuffer[9] = (unsigned char)(xvdd->bytes_per_sector >> 16) & 0xff;
   1.269 +      DataBuffer[10] = (unsigned char)(xvdd->bytes_per_sector >> 8) & 0xff;
   1.270 +      DataBuffer[11] = (unsigned char)(xvdd->bytes_per_sector >> 0) & 0xff;
   1.271 +      Srb->ScsiStatus = 0;
   1.272 +      Srb->SrbStatus = SRB_STATUS_SUCCESS;
   1.273 +      break;
   1.274      case SCSIOP_MODE_SENSE:
   1.275 +    case SCSIOP_MODE_SENSE10:
   1.276  //      KdPrint((__DRIVER_NAME "     Command = MODE_SENSE (DBD = %d, PC = %d, Page Code = %02x)\n", Srb->Cdb[1] & 0x08, Srb->Cdb[2] & 0xC0, Srb->Cdb[2] & 0x3F));
   1.277        XenVbd_FillModePage(xvdd, Srb);
   1.278        break;
   1.279 +    case SCSIOP_READ:
   1.280 +    case SCSIOP_READ16:
   1.281      case SCSIOP_WRITE:
   1.282 -    case SCSIOP_READ:
   1.283 +    case SCSIOP_WRITE16:
   1.284  //      KdPrint((__DRIVER_NAME "     Command = READ/WRITE\n"));
   1.285        XenVbd_PutSrbOnRing(xvdd, Srb, 0);
   1.286        break;
   1.287 @@ -1219,7 +1336,7 @@ XenVbd_HwScsiStartIo(PVOID DeviceExtensi
   1.288        Srb->SrbStatus = SRB_STATUS_SUCCESS;
   1.289        break;
   1.290      default:
   1.291 -      //KdPrint((__DRIVER_NAME "     Unhandled EXECUTE_SCSI Command = %02X\n", Srb->Cdb[0]));
   1.292 +      KdPrint((__DRIVER_NAME "     Unhandled EXECUTE_SCSI Command = %02X\n", Srb->Cdb[0]));
   1.293        Srb->SrbStatus = SRB_STATUS_ERROR;
   1.294        break;
   1.295      }
   1.296 @@ -1257,7 +1374,7 @@ XenVbd_HwScsiStartIo(PVOID DeviceExtensi
   1.297      ScsiPortNotification(NextLuRequest, DeviceExtension, 0, 0, 0);
   1.298      break;
   1.299    default:
   1.300 -    //KdPrint((__DRIVER_NAME "     Unhandled Srb->Function = %08X\n", Srb->Function));
   1.301 +    KdPrint((__DRIVER_NAME "     Unhandled Srb->Function = %08X\n", Srb->Function));
   1.302      Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
   1.303      ScsiPortNotification(RequestComplete, DeviceExtension, Srb);
   1.304      ScsiPortNotification(NextLuRequest, DeviceExtension, 0, 0, 0);