linux/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
<<
>>
Prefs
   1/*
   2 * Scsi Host Layer for MPT (Message Passing Technology) based controllers
   3 *
   4 * Copyright (C) 2012-2014  LSI Corporation
   5 * Copyright (C) 2013-2015 Avago Technologies
   6 *  (mailto: MPT-FusionLinux.pdl@avagotech.com)
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * NO WARRANTY
  19 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
  20 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
  21 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
  22 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
  23 * solely responsible for determining the appropriateness of using and
  24 * distributing the Program and assumes all risks associated with its
  25 * exercise of rights under this Agreement, including but not limited to
  26 * the risks and costs of program errors, damage to or loss of data,
  27 * programs or equipment, and unavailability or interruption of operations.
  28
  29 * DISCLAIMER OF LIABILITY
  30 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
  31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
  33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  35 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
  36 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
  37
  38 * You should have received a copy of the GNU General Public License
  39 * along with this program.
  40 */
  41#include <linux/kernel.h>
  42#include <linux/module.h>
  43#include <linux/errno.h>
  44#include <linux/types.h>
  45#include <asm/unaligned.h>
  46
  47#include "mpt3sas_base.h"
  48
  49/**
  50 * _warpdrive_disable_ddio - Disable direct I/O for all the volumes
  51 * @ioc: per adapter object
  52 */
  53static void
  54_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc)
  55{
  56        Mpi2RaidVolPage1_t vol_pg1;
  57        Mpi2ConfigReply_t mpi_reply;
  58        struct _raid_device *raid_device;
  59        u16 handle;
  60        u16 ioc_status;
  61        unsigned long flags;
  62
  63        handle = 0xFFFF;
  64        while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
  65            &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
  66                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
  67                    MPI2_IOCSTATUS_MASK;
  68                if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
  69                        break;
  70                handle = le16_to_cpu(vol_pg1.DevHandle);
  71                spin_lock_irqsave(&ioc->raid_device_lock, flags);
  72                raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
  73                if (raid_device)
  74                        raid_device->direct_io_enabled = 0;
  75                spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
  76        }
  77        return;
  78}
  79
  80
  81/**
  82 * mpt3sas_get_num_volumes - Get number of volumes in the ioc
  83 * @ioc: per adapter object
  84 */
  85u8
  86mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc)
  87{
  88        Mpi2RaidVolPage1_t vol_pg1;
  89        Mpi2ConfigReply_t mpi_reply;
  90        u16 handle;
  91        u8 vol_cnt = 0;
  92        u16 ioc_status;
  93
  94        handle = 0xFFFF;
  95        while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
  96            &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
  97                ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
  98                    MPI2_IOCSTATUS_MASK;
  99                if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
 100                        break;
 101                vol_cnt++;
 102                handle = le16_to_cpu(vol_pg1.DevHandle);
 103        }
 104        return vol_cnt;
 105}
 106
 107
 108/**
 109 * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O.
 110 * @ioc: per adapter object
 111 * @raid_device: the raid_device object
 112 */
 113void
 114mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
 115        struct _raid_device *raid_device)
 116{
 117        Mpi2RaidVolPage0_t *vol_pg0;
 118        Mpi2RaidPhysDiskPage0_t pd_pg0;
 119        Mpi2ConfigReply_t mpi_reply;
 120        u16 sz;
 121        u8 num_pds, count;
 122        unsigned long stripe_sz, block_sz;
 123        u8 stripe_exp, block_exp;
 124        u64 dev_max_lba;
 125
 126        if (!ioc->is_warpdrive)
 127                return;
 128
 129        if (ioc->mfg_pg10_hide_flag ==  MFG_PAGE10_EXPOSE_ALL_DISKS) {
 130                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 131                    "globally as drives are exposed\n", ioc->name);
 132                return;
 133        }
 134        if (mpt3sas_get_num_volumes(ioc) > 1) {
 135                _warpdrive_disable_ddio(ioc);
 136                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 137                    "globally as number of drives > 1\n", ioc->name);
 138                return;
 139        }
 140        if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
 141            &num_pds)) || !num_pds) {
 142                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 143                    "Failure in computing number of drives\n", ioc->name);
 144                return;
 145        }
 146
 147        sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
 148            sizeof(Mpi2RaidVol0PhysDisk_t));
 149        vol_pg0 = kzalloc(sz, GFP_KERNEL);
 150        if (!vol_pg0) {
 151                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 152                    "Memory allocation failure for RVPG0\n", ioc->name);
 153                return;
 154        }
 155
 156        if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
 157             MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
 158                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 159                    "Failure in retrieving RVPG0\n", ioc->name);
 160                kfree(vol_pg0);
 161                return;
 162        }
 163
 164        /*
 165         * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
 166         * assumed for WARPDRIVE, disable direct I/O
 167         */
 168        if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
 169                pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 170                    "for the drive with handle(0x%04x): num_mem=%d, "
 171                    "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
 172                    num_pds, MPT_MAX_WARPDRIVE_PDS);
 173                kfree(vol_pg0);
 174                return;
 175        }
 176        for (count = 0; count < num_pds; count++) {
 177                if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
 178                    &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
 179                    vol_pg0->PhysDisk[count].PhysDiskNum) ||
 180                    pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) {
 181                        pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
 182                            "disabled for the drive with handle(0x%04x) member"
 183                            "handle retrieval failed for member number=%d\n",
 184                            ioc->name, raid_device->handle,
 185                            vol_pg0->PhysDisk[count].PhysDiskNum);
 186                        goto out_error;
 187                }
 188                /* Disable direct I/O if member drive lba exceeds 4 bytes */
 189                dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
 190                if (dev_max_lba >> 32) {
 191                        pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
 192                            "disabled for the drive with handle(0x%04x) member"
 193                            " handle (0x%04x) unsupported max lba 0x%016llx\n",
 194                            ioc->name, raid_device->handle,
 195                            le16_to_cpu(pd_pg0.DevHandle),
 196                            (unsigned long long)dev_max_lba);
 197                        goto out_error;
 198                }
 199
 200                raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
 201        }
 202
 203        /*
 204         * Assumption for WD: Direct I/O is not supported if the volume is
 205         * not RAID0
 206         */
 207        if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
 208                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 209                    "for the drive with handle(0x%04x): type=%d, "
 210                    "s_sz=%uK, blk_size=%u\n", ioc->name,
 211                    raid_device->handle, raid_device->volume_type,
 212                    (le32_to_cpu(vol_pg0->StripeSize) *
 213                    le16_to_cpu(vol_pg0->BlockSize)) / 1024,
 214                    le16_to_cpu(vol_pg0->BlockSize));
 215                goto out_error;
 216        }
 217
 218        stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
 219        stripe_exp = find_first_bit(&stripe_sz, 32);
 220        if (stripe_exp == 32) {
 221                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 222                "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
 223                    ioc->name, raid_device->handle,
 224                    (le32_to_cpu(vol_pg0->StripeSize) *
 225                    le16_to_cpu(vol_pg0->BlockSize)) / 1024);
 226                goto out_error;
 227        }
 228        raid_device->stripe_exponent = stripe_exp;
 229        block_sz = le16_to_cpu(vol_pg0->BlockSize);
 230        block_exp = find_first_bit(&block_sz, 16);
 231        if (block_exp == 16) {
 232                pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
 233                    "for the drive with handle(0x%04x) invalid block sz %u\n",
 234                    ioc->name, raid_device->handle,
 235                    le16_to_cpu(vol_pg0->BlockSize));
 236                goto out_error;
 237        }
 238        raid_device->block_exponent = block_exp;
 239        raid_device->direct_io_enabled = 1;
 240
 241        pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
 242            " with handle(0x%04x)\n", ioc->name, raid_device->handle);
 243        /*
 244         * WARPDRIVE: Though the following fields are not used for direct IO,
 245         * stored for future purpose:
 246         */
 247        raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
 248        raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
 249        raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
 250
 251
 252        kfree(vol_pg0);
 253        return;
 254
 255out_error:
 256        raid_device->direct_io_enabled = 0;
 257        for (count = 0; count < num_pds; count++)
 258                raid_device->pd_handle[count] = 0;
 259        kfree(vol_pg0);
 260        return;
 261}
 262
 263/**
 264 * mpt3sas_scsi_direct_io_get - returns direct io flag
 265 * @ioc: per adapter object
 266 * @smid: system request message index
 267 *
 268 * Returns the smid stored scmd pointer.
 269 */
 270inline u8
 271mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
 272{
 273        return ioc->scsi_lookup[smid - 1].direct_io;
 274}
 275
 276/**
 277 * mpt3sas_scsi_direct_io_set - sets direct io flag
 278 * @ioc: per adapter object
 279 * @smid: system request message index
 280 * @direct_io: Zero or non-zero value to set in the direct_io flag
 281 *
 282 * Returns Nothing.
 283 */
 284inline void
 285mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
 286{
 287        ioc->scsi_lookup[smid - 1].direct_io = direct_io;
 288}
 289
 290/**
 291 * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
 292 * @ioc: per adapter object
 293 * @scmd: pointer to scsi command object
 294 * @raid_device: pointer to raid device data structure
 295 * @mpi_request: pointer to the SCSI_IO reqest message frame
 296 * @smid: system request message index
 297 *
 298 * Returns nothing
 299 */
 300void
 301mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
 302        struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
 303        u16 smid)
 304{
 305        sector_t v_lba, p_lba, stripe_off, column, io_size;
 306        u32 stripe_sz, stripe_exp;
 307        u8 num_pds, cmd = scmd->cmnd[0];
 308
 309        if (cmd != READ_10 && cmd != WRITE_10 &&
 310            cmd != READ_16 && cmd != WRITE_16)
 311                return;
 312
 313        if (cmd == READ_10 || cmd == WRITE_10)
 314                v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
 315        else
 316                v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
 317
 318        io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
 319
 320        if (v_lba + io_size - 1 > raid_device->max_lba)
 321                return;
 322
 323        stripe_sz = raid_device->stripe_sz;
 324        stripe_exp = raid_device->stripe_exponent;
 325        stripe_off = v_lba & (stripe_sz - 1);
 326
 327        /* Return unless IO falls within a stripe */
 328        if (stripe_off + io_size > stripe_sz)
 329                return;
 330
 331        num_pds = raid_device->num_pds;
 332        p_lba = v_lba >> stripe_exp;
 333        column = sector_div(p_lba, num_pds);
 334        p_lba = (p_lba << stripe_exp) + stripe_off;
 335        mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
 336
 337        if (cmd == READ_10 || cmd == WRITE_10)
 338                put_unaligned_be32(lower_32_bits(p_lba),
 339                                   &mpi_request->CDB.CDB32[2]);
 340        else
 341                put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
 342
 343        mpt3sas_scsi_direct_io_set(ioc, smid, 1);
 344}
 345