diff options
| author | nagalakshmi.nandigama@lsi.com <nagalakshmi.nandigama@lsi.com> | 2011-12-01 07:51:55 +0530 | 
|---|---|---|
| committer | James Bottomley <JBottomley@Parallels.com> | 2011-12-15 10:57:33 +0400 | 
| commit | ba96bd0b1d4a4e11f23671e1f375a5c8f46b0fe7 (patch) | |
| tree | 7db0fcd7efbc8b3fcf9bdb88e1ffef1fda9fc78e /drivers/scsi/mpt2sas | |
| parent | 7509d6bb955d08c4125bcf44650b2df839470bf8 (diff) | |
| download | olio-linux-3.10-ba96bd0b1d4a4e11f23671e1f375a5c8f46b0fe7.tar.xz olio-linux-3.10-ba96bd0b1d4a4e11f23671e1f375a5c8f46b0fe7.zip  | |
[SCSI] mpt2sas: Support for greater than 2TB capacity WarpDrive
The driver is modified to allow access to the greater than 2TB WarpDrive
and properly handle direct-io mapping for WarpDrive volumes greater than 2TB.
Signed-off-by: Nagalakshmi Nandigama <nagalakshmi.nandigama@lsi.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/mpt2sas')
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_base.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/mpt2sas/mpt2sas_scsih.c | 115 | 
2 files changed, 74 insertions, 43 deletions
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index b3b03bb8ab5..88ead5ed2af 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -374,6 +374,7 @@ struct _sas_device {   * @percent_complete: resync percent complete   * @direct_io_enabled: Whether direct io to PDs are allowed or not   * @stripe_exponent: X where 2powX is the stripe sz in blocks + * @block_exponent: X where 2powX is the block sz in bytes   * @max_lba: Maximum number of LBA in the volume   * @stripe_sz: Stripe Size of the volume   * @device_info: Device info of the volume member disk @@ -395,6 +396,7 @@ struct _raid_device {  	u8	percent_complete;  	u8	direct_io_enabled;  	u8	stripe_exponent; +	u8	block_exponent;  	u64	max_lba;  	u32	stripe_sz;  	u32	device_info; diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index a9efc455108..ba8171fe17e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -1780,11 +1780,9 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,  	Mpi2ConfigReply_t mpi_reply;  	u16 sz;  	u8 num_pds, count; -	u64 mb = 1024 * 1024; -	u64 tb_2 = 2 * mb * mb; -	u64 capacity; -	u32 stripe_sz; -	u8 i, stripe_exp; +	unsigned long stripe_sz, block_sz; +	u8 stripe_exp, block_exp; +	u64 dev_max_lba;  	if (!ioc->is_warpdrive)  		return; @@ -1848,51 +1846,57 @@ _scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,  			    vol_pg0->PhysDisk[count].PhysDiskNum);  			goto out_error;  		} +		/* Disable direct I/O if member drive lba exceeds 4 bytes */ +		dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); +		if (dev_max_lba >> 32) { +			printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " +			    "disabled for the drive with handle(0x%04x) member" +			    "handle (0x%04x) unsupported max lba 0x%016llx\n", +			    ioc->name, raid_device->handle, +			    le16_to_cpu(pd_pg0.DevHandle), +			    (unsigned long long)dev_max_lba); +			goto out_error; +		} +  		raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);  	}  	/*  	 * Assumption for WD: Direct I/O is not supported if the volume is -	 * not RAID0, if the stripe size is not 64KB, if the block size is -	 * not 512 and if the volume size is >2TB +	 * not RAID0  	 */ -	if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0 || -	    le16_to_cpu(vol_pg0->BlockSize) != 512) { +	if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {  		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "  		    "for the drive with handle(0x%04x): type=%d, "  		    "s_sz=%uK, blk_size=%u\n", ioc->name,  		    raid_device->handle, raid_device->volume_type, -		    le32_to_cpu(vol_pg0->StripeSize)/2, +		    (le32_to_cpu(vol_pg0->StripeSize) * +		    le16_to_cpu(vol_pg0->BlockSize)) / 1024,  		    le16_to_cpu(vol_pg0->BlockSize));  		goto out_error;  	} -	capacity = (u64) le16_to_cpu(vol_pg0->BlockSize) * -	    (le64_to_cpu(vol_pg0->MaxLBA) + 1); - -	if (capacity > tb_2) { +	stripe_sz = le32_to_cpu(vol_pg0->StripeSize); +	stripe_exp = find_first_bit(&stripe_sz, 32); +	if (stripe_exp == 32) {  		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " -		"for the drive with handle(0x%04x) since drive sz > 2TB\n", -		ioc->name, raid_device->handle); +		"for the drive with handle(0x%04x) invalid stripe sz %uK\n", +		    ioc->name, raid_device->handle, +		    (le32_to_cpu(vol_pg0->StripeSize) * +		    le16_to_cpu(vol_pg0->BlockSize)) / 1024);  		goto out_error;  	} - -	stripe_sz = le32_to_cpu(vol_pg0->StripeSize); -	stripe_exp = 0; -	for (i = 0; i < 32; i++) { -		if (stripe_sz & 1) -			break; -		stripe_exp++; -		stripe_sz >>= 1; -	} -	if (i == 32) { +	raid_device->stripe_exponent = stripe_exp; +	block_sz = le16_to_cpu(vol_pg0->BlockSize); +	block_exp = find_first_bit(&block_sz, 16); +	if (block_exp == 16) {  		printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " -		    "for the drive with handle(0x%04x) invalid stripe sz %uK\n", +		    "for the drive with handle(0x%04x) invalid block sz %u\n",  		    ioc->name, raid_device->handle, -		    le32_to_cpu(vol_pg0->StripeSize)/2); +		    le16_to_cpu(vol_pg0->BlockSize));  		goto out_error;  	} -	raid_device->stripe_exponent = stripe_exp; +	raid_device->block_exponent = block_exp;  	raid_device->direct_io_enabled = 1;  	printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" @@ -3808,8 +3812,9 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  {  	u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size;  	u32 stripe_sz, stripe_exp; -	u8 num_pds, *cdb_ptr, *tmp_ptr, *lba_ptr1, *lba_ptr2; +	u8 num_pds, *cdb_ptr, i;  	u8 cdb0 = scmd->cmnd[0]; +	u64 v_llba;  	/*  	 * Try Direct I/O to RAID memeber disks @@ -3820,15 +3825,11 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  		if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4]  			| cdb_ptr[5])) { -			io_size = scsi_bufflen(scmd) >> 9; +			io_size = scsi_bufflen(scmd) >> +			    raid_device->block_exponent; +			i = (cdb0 < READ_16) ? 2 : 6;  			/* get virtual lba */ -			lba_ptr1 = lba_ptr2 = (cdb0 < READ_16) ? &cdb_ptr[2] : -			    &cdb_ptr[6]; -			tmp_ptr = (u8 *)&v_lba + 3; -			*tmp_ptr-- = *lba_ptr1++; -			*tmp_ptr-- = *lba_ptr1++; -			*tmp_ptr-- = *lba_ptr1++; -			*tmp_ptr = *lba_ptr1; +			v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i]));  			if (((u64)v_lba + (u64)io_size - 1) <=  			    (u32)raid_device->max_lba) { @@ -3847,11 +3848,39 @@ _scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,  					mpi_request->DevHandle =  						cpu_to_le16(raid_device->  						    pd_handle[column]); -					tmp_ptr = (u8 *)&p_lba + 3; -					*lba_ptr2++ = *tmp_ptr--; -					*lba_ptr2++ = *tmp_ptr--; -					*lba_ptr2++ = *tmp_ptr--; -					*lba_ptr2 = *tmp_ptr; +					(*(__be32 *)(&cdb_ptr[i])) = +						cpu_to_be32(p_lba); +					/* +					* WD: To indicate this I/O is directI/O +					*/ +					_scsih_scsi_direct_io_set(ioc, smid, 1); +				} +			} +		} else { +			io_size = scsi_bufflen(scmd) >> +			    raid_device->block_exponent; +			/* get virtual lba */ +			v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); + +			if ((v_llba + (u64)io_size - 1) <= +			    raid_device->max_lba) { +				stripe_sz = raid_device->stripe_sz; +				stripe_exp = raid_device->stripe_exponent; +				stripe_off = (u32) (v_llba & (stripe_sz - 1)); + +				/* Check whether IO falls within a stripe */ +				if ((stripe_off + io_size) <= stripe_sz) { +					num_pds = raid_device->num_pds; +					p_lba = (u32)(v_llba >> stripe_exp); +					stripe_unit = p_lba / num_pds; +					column = p_lba % num_pds; +					p_lba = (stripe_unit << stripe_exp) + +					    stripe_off; +					mpi_request->DevHandle = +						cpu_to_le16(raid_device-> +						    pd_handle[column]); +					(*(__be64 *)(&cdb_ptr[2])) = +					    cpu_to_be64((u64)p_lba);  					/*  					* WD: To indicate this I/O is directI/O  					*/  |