Release 4.11 drivers/scsi/megaraid.c
/*
*
* Linux MegaRAID device driver
*
* Copyright (c) 2002 LSI Logic Corporation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Copyright (c) 2002 Red Hat, Inc. All rights reserved.
* - fixes
* - speed-ups (list handling fixes, issued_list, optimizations.)
* - lots of cleanups.
*
* Copyright (c) 2003 Christoph Hellwig <hch@lst.de>
* - new-style, hotplug-aware pci probing and scsi registration
*
* Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju
* <Seokmann.Ju@lsil.com>
*
* Description: Linux device driver for LSI Logic MegaRAID controller
*
* Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493
* 518, 520, 531, 532
*
* This driver is supported by LSI Logic, with assistance from Red Hat, Dell,
* and others. Please send updates to the mailing list
* linux-scsi@vger.kernel.org .
*
*/
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/uaccess.h>
#include <asm/io.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <scsi/scsicam.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "megaraid.h"
#define MEGARAID_MODULE_VERSION "2.00.4"
MODULE_AUTHOR ("sju@lsil.com");
MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver");
MODULE_LICENSE ("GPL");
MODULE_VERSION(MEGARAID_MODULE_VERSION);
static DEFINE_MUTEX(megadev_mutex);
static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN;
module_param(max_cmd_per_lun, uint, 0);
MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)");
static unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO;
module_param(max_sectors_per_io, ushort, 0);
MODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)");
static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;
module_param(max_mbox_busy_wait, ushort, 0);
MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");
#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20)
#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C)
#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20)
#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C)
/*
* Global variables
*/
static int hba_count;
static adapter_t *hba_soft_state[MAX_CONTROLLERS];
static struct proc_dir_entry *mega_proc_dir_entry;
/* For controller re-ordering */
static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
static long
megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
/*
* The File Operations structure for the serial/ioctl interface of the driver
*/
static const struct file_operations megadev_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = megadev_unlocked_ioctl,
.open = megadev_open,
.llseek = noop_llseek,
};
/*
* Array to structures for storing the information about the controllers. This
* information is sent to the user level applications, when they do an ioctl
* for this information.
*/
static struct mcontroller mcontroller[MAX_CONTROLLERS];
/* The current driver version */
static u32 driver_ver = 0x02000000;
/* major number used by the device for character interface */
static int major;
#define IS_RAID_CH(hba, ch) (((hba)->mega_ch_class >> (ch)) & 0x01)
/*
* Debug variable to print some diagnostic messages
*/
static int trace_level;
/**
* mega_setup_mailbox()
* @adapter - pointer to our soft state
*
* Allocates a 8 byte aligned memory for the handshake mailbox.
*/
static int
mega_setup_mailbox(adapter_t *adapter)
{
unsigned long align;
adapter->una_mbox64 = pci_alloc_consistent(adapter->dev,
sizeof(mbox64_t), &adapter->una_mbox64_dma);
if( !adapter->una_mbox64 ) return -1;
adapter->mbox = &adapter->una_mbox64->mbox;
adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) &
(~0UL ^ 0xFUL));
adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8);
align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox);
adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align;
/*
* Register the mailbox if the controller is an io-mapped controller
*/
if( adapter->flag & BOARD_IOMAP ) {
outb(adapter->mbox_dma & 0xFF,
adapter->host->io_port + MBOX_PORT0);
outb((adapter->mbox_dma >> 8) & 0xFF,
adapter->host->io_port + MBOX_PORT1);
outb((adapter->mbox_dma >> 16) & 0xFF,
adapter->host->io_port + MBOX_PORT2);
outb((adapter->mbox_dma >> 24) & 0xFF,
adapter->host->io_port + MBOX_PORT3);
outb(ENABLE_MBOX_BYTE,
adapter->host->io_port + ENABLE_MBOX_REGION);
irq_ack(adapter);
irq_enable(adapter);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 220 | 83.33% | 1 | 20.00% |
Atul Mukker | 32 | 12.12% | 1 | 20.00% |
Linus Torvalds | 6 | 2.27% | 1 | 20.00% |
Alan Cox | 5 | 1.89% | 1 | 20.00% |
Linus Torvalds (pre-git) | 1 | 0.38% | 1 | 20.00% |
Total | 264 | 100.00% | 5 | 100.00% |
/*
* mega_query_adapter()
* @adapter - pointer to our soft state
*
* Issue the adapter inquiry commands to the controller and find out
* information and parameter about the devices attached
*/
static int
mega_query_adapter(adapter_t *adapter)
{
dma_addr_t prod_info_dma_handle;
mega_inquiry3 *inquiry3;
u8 raw_mbox[sizeof(struct mbox_out)];
mbox_t *mbox;
int retval;
/* Initialize adapter inquiry mailbox */
mbox = (mbox_t *)raw_mbox;
memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
memset(&mbox->m_out, 0, sizeof(raw_mbox));
/*
* Try to issue Inquiry3 command
* if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
* update enquiry3 structure
*/
mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
inquiry3 = (mega_inquiry3 *)adapter->mega_buffer;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */
raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */
/* Issue a blocking command to the card */
if ((retval = issue_scb_block(adapter, raw_mbox))) {
/* the adapter does not support 40ld */
mraid_ext_inquiry *ext_inq;
mraid_inquiry *inq;
dma_addr_t dma_handle;
ext_inq = pci_alloc_consistent(adapter->dev,
sizeof(mraid_ext_inquiry), &dma_handle);
if( ext_inq == NULL ) return -1;
inq = &ext_inq->raid_inq;
mbox->m_out.xferaddr = (u32)dma_handle;
/*issue old 0x04 command to adapter */
mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ;
issue_scb_block(adapter, raw_mbox);
/*
* update Enquiry3 and ProductInfo structures with
* mraid_inquiry structure
*/
mega_8_to_40ld(inq, inquiry3,
(mega_product_info *)&adapter->product_info);
pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry),
ext_inq, dma_handle);
} else { /*adapter supports 40ld */
adapter->flag |= BOARD_40LD;
/*
* get product_info, which is static information and will be
* unchanged
*/
prod_info_dma_handle = pci_map_single(adapter->dev, (void *)
&adapter->product_info,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
mbox->m_out.xferaddr = prod_info_dma_handle;
raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */
raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */
if ((retval = issue_scb_block(adapter, raw_mbox)))
dev_warn(&adapter->dev->dev,
"Product_info cmd failed with error: %d\n",
retval);
pci_unmap_single(adapter->dev, prod_info_dma_handle,
sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
}
/*
* kernel scans the channels from 0 to <= max_channel
*/
adapter->host->max_channel =
adapter->product_info.nchannels + NVIRT_CHAN -1;
adapter->host->max_id = 16; /* max targets per channel */
adapter->host->max_lun = 7; /* Up to 7 luns for non disk devices */
adapter->host->cmd_per_lun = max_cmd_per_lun;
adapter->numldrv = inquiry3->num_ldrv;
adapter->max_cmds = adapter->product_info.max_commands;
if(adapter->max_cmds > MAX_COMMANDS)
adapter->max_cmds = MAX_COMMANDS;
adapter->host->can_queue = adapter->max_cmds - 1;
/*
* Get the maximum number of scatter-gather elements supported by this
* firmware
*/
mega_get_max_sgl(adapter);
adapter->host->sg_tablesize = adapter->sglen;
/* use HP firmware and bios version encoding
Note: fw_version[0|1] and bios_version[0|1] were originally shifted
right 8 bits making them zero. This 0 value was hardcoded to fix
sparse warnings. */
if (adapter->product_info.subsysvid == PCI_VENDOR_ID_HP) {
sprintf (adapter->fw_version, "%c%d%d.%d%d",
adapter->product_info.fw_version[2],
0,
adapter->product_info.fw_version[1] & 0x0f,
0,
adapter->product_info.fw_version[0] & 0x0f);
sprintf (adapter->bios_version, "%c%d%d.%d%d",
adapter->product_info.bios_version[2],
0,
adapter->product_info.bios_version[1] & 0x0f,
0,
adapter->product_info.bios_version[0] & 0x0f);
} else {
memcpy(adapter->fw_version,
(char *)adapter->product_info.fw_version, 4);
adapter->fw_version[4] = 0;
memcpy(adapter->bios_version,
(char *)adapter->product_info.bios_version, 4);
adapter->bios_version[4] = 0;
}
dev_notice(&adapter->dev->dev, "[%s:%s] detected %d logical drives\n",
adapter->fw_version, adapter->bios_version, adapter->numldrv);
/*
* Do we support extended (>10 bytes) cdbs
*/
adapter->support_ext_cdb = mega_support_ext_cdb(adapter);
if (adapter->support_ext_cdb)
dev_notice(&adapter->dev->dev, "supports extended CDBs\n");
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 420 | 63.25% | 1 | 11.11% |
Atul Mukker | 116 | 17.47% | 1 | 11.11% |
Linus Torvalds | 95 | 14.31% | 2 | 22.22% |
Björn Helgaas | 27 | 4.07% | 1 | 11.11% |
Adam Radford | 3 | 0.45% | 1 | 11.11% |
Jon Mason | 1 | 0.15% | 1 | 11.11% |
Jason Holmes | 1 | 0.15% | 1 | 11.11% |
Lucas De Marchi | 1 | 0.15% | 1 | 11.11% |
Total | 664 | 100.00% | 9 | 100.00% |
/**
* mega_runpendq()
* @adapter - pointer to our soft state
*
* Runs through the list of pending requests.
*/
static inline void
mega_runpendq(adapter_t *adapter)
{
if(!list_empty(&adapter->pending_list))
__mega_runpendq(adapter);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
/*
* megaraid_queue()
* @scmd - Issue this scsi command
* @done - the callback hook into the scsi mid-layer
*
* The command queuing entry point for the mid-layer.
*/
static int
megaraid_queue_lck(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
{
adapter_t *adapter;
scb_t *scb;
int busy=0;
unsigned long flags;
adapter = (adapter_t *)scmd->device->host->hostdata;
scmd->scsi_done = done;
/*
* Allocate and build a SCB request
* busy flag will be set if mega_build_cmd() command could not
* allocate scb. We will return non-zero status in that case.
* NOTE: scb can be null even though certain commands completed
* successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
* return 0 in that case.
*/
spin_lock_irqsave(&adapter->lock, flags);
scb = mega_build_cmd(adapter, scmd, &busy);
if (!scb)
goto out;
scb->state |= SCB_PENDQ;
list_add_tail(&scb->list, &adapter->pending_list);
/*
* Check if the HBA is in quiescent state, e.g., during a
* delete logical drive opertion. If it is, don't run
* the pending_list.
*/
if (atomic_read(&adapter->quiescent) == 0)
mega_runpendq(adapter);
busy = 0;
out:
spin_unlock_irqrestore(&adapter->lock, flags);
return busy;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Christoph Hellwig | 109 | 75.69% | 3 | 42.86% |
Atul Mukker | 17 | 11.81% | 1 | 14.29% |
Linus Torvalds | 17 | 11.81% | 2 | 28.57% |
Jeff Garzik | 1 | 0.69% | 1 | 14.29% |
Total | 144 | 100.00% | 7 | 100.00% |
static DEF_SCSI_QCMD(megaraid_queue)
/**
* mega_allocate_scb()
* @adapter - pointer to our soft state
* @cmd - scsi command from the mid-layer
*
* Allocate a SCB structure. This is the central structure for controller
* commands.
*/
static inline scb_t *
mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd)
{
struct list_head *head = &adapter->free_list;
scb_t *scb;
/* Unlink command from Free List */
if( !list_empty(head) ) {
scb = list_entry(head->next, scb_t, list);
list_del_init(head->next);
scb->state = SCB_ACTIVE;
scb->cmd = cmd;
scb->dma_type = MEGA_DMA_TYPE_NONE;
return scb;
}
return NULL;
}
/**
* mega_get_ldrv_num()
* @adapter - pointer to our soft state
* @cmd - scsi mid layer command
* @channel - channel on the controller
*
* Calculate the logical drive number based on the information in scsi command
* and the channel number.
*/
static inline int
mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel)
{
int tgt;
int ldrv_num;
tgt = cmd->device->id;
if ( tgt > adapter->this_id )
tgt--; /* we do not get inquires for initiator id */
ldrv_num = (channel * 15) + tgt;
/*
* If we have a logical drive with boot enabled, project it first
*/
if( adapter->boot_ldrv_enabled ) {
if( ldrv_num == 0 ) {
ldrv_num = adapter->boot_ldrv;
}
else {
if( ldrv_num <= adapter->boot_ldrv ) {
ldrv_num--;
}
}
}
/*
* If "delete logical drive" feature is enabled on this controller.
* Do only if at least one delete logical drive operation was done.
*
* Also, after logical drive deletion, instead of logical drive number,
* the value returned should be 0x80+logical drive id.
*
* These is valid only for IO commands.
*/
if (adapter->support_random_del && adapter->read_ldidmap )
switch (cmd->cmnd[0]) {
case READ_6: /* fall through */
case WRITE_6: /* fall through */
case READ_10: /* fall through */
case WRITE_10:
ldrv_num += 0x80;
}
return ldrv_num;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Al Viro | 136 | 99.27% | 1 | 50.00% |
Jeff Garzik | 1 | 0.73% | 1 | 50.00% |
Total | 137 | 100.00% | 2 | 100.00% |
/**
* mega_build_cmd()
* @adapter - pointer to our soft state
* @cmd - Prepare using this scsi command
* @busy - busy flag if no resources
*
* Prepares a command and scatter gather list for the controller. This routine
* also finds out if the commands is intended for a logical drive or a
* physical device and prepares the controller command accordingly.
*
* We also re-order the logical drives and physical devices based on their
* boot settings.
*/
static scb_t *
mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
{
mega_ext_passthru *epthru;
mega_passthru *pthru;
scb_t *scb;
mbox_t *mbox;
u32 seg;
char islogical;
int max_ldrv_num;
int channel = 0;
int target = 0;
int ldrv_num = 0; /* logical drive number */
/*
* We know what channels our logical drives are on - mega_find_card()
*/
islogical = adapter->logdrv_chan[cmd->device->channel];
/*
* The theory: If physical drive is chosen for boot, all the physical
* devices are exported before the logical drives, otherwise physical
* devices are pushed after logical drives, in which case - Kernel sees
* the physical devices on virtual channel which is obviously converted
* to actual channel on the HBA.
*/
if( adapter->boot_pdrv_enabled ) {
if( islogical ) {
/* logical channel */
channel = cmd->device->channel -
adapter->product_info.nchannels;
}
else {
/* this is physical channel */
channel = cmd->device->channel;
target = cmd->device->id;
/*
* boot from a physical disk, that disk needs to be
* exposed first IF both the channels are SCSI, then
* booting from the second channel is not allowed.
*/
if( target == 0 ) {
target = adapter->boot_pdrv_tgt;
}
else if( target == adapter->boot_pdrv_tgt ) {
target = 0;
}
}
}
else {
if( islogical ) {
/* this is the logical channel */
channel = cmd->device->channel;
}
else {
/* physical channel */
channel = cmd->device->channel - NVIRT_CHAN;
target = cmd->device->id;
}
}
if(islogical) {
/* have just LUN 0 for each target on virtual channels */
if (cmd->device->lun) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
ldrv_num = mega_get_ldrv_num(adapter, cmd, channel);
max_ldrv_num = (adapter->flag & BOARD_40LD) ?
MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD;
/*
* max_ldrv_num increases by 0x80 if some logical drive was
* deleted.
*/
if(adapter->read_ldidmap)
max_ldrv_num += 0x80;
if(ldrv_num > max_ldrv_num ) {
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
}
else {
if( cmd->device->lun > 7) {
/*
* Do not support lun >7 for physically accessed
* devices
*/
cmd->result = (DID_BAD_TARGET << 16);
cmd->scsi_done(cmd);
return NULL;
}
}
/*
*
* Logical drive commands
*
*/
if(islogical) {
switch (cmd->cmnd[0]) {
case TEST_UNIT_READY:
#if MEGA_HAVE_CLUSTERING
/*
* Do we support clustering and is the support enabled
* If no, return success always
*/
if( !adapter->has_cluster ) {
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
}
if(!(scb = mega_allocate_scb(adapter, cmd))) {
*busy = 1;
return NULL;
}
scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
scb->raw_mbox[2] = MEGA_RESERVATION_STATUS;
scb->raw_mbox[3] = ldrv_num;
scb->dma_direction = PCI_DMA_NONE;
return scb;
#else
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
#endif
case MODE_SENSE: {
char *buf;
struct scatterlist *sg;
sg = scsi_sglist(cmd);
buf = kmap_atomic(sg_page(sg)) + sg->offset;
memset(buf, 0, cmd->cmnd[4]);
kunmap_atomic(buf - sg->offset);
cmd->result = (DID_OK << 16);
cmd->scsi_done(cmd);
return NULL;
}
case READ_CAPACITY:
case INQUIRY:
if(!(adapter->flag & (1L << cmd->device->channel))) {
dev_notice(&adapter->dev->dev,
"scsi%d: scanning scsi channel %d "
"for logical drives\n",
adapter->host->host_no,
cmd->device->channel);
adapter->flag |= (1L << cmd->device->channel);
}
/* Allocate a SCB and initialize passthru */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
*busy = 1;
return NULL;
}
pthru = scb->pthru;
mbox = (mbox_t *)scb->raw_mbox;
memset(mbox, 0, sizeof(scb->raw_mbox));
memset(pthru, 0, sizeof(mega_passthru));
pthru->timeout = 0;
pthru->ars = 1;
pthru->reqsenselen = 14;
pthru->islogical = 1;
pthru->logdrv = ldrv_num;
pthru->cdblen = cmd->cmd_len;
memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len);
if( adapter->has_64bit_addr ) {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64;
}
else {
mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU;
}
scb->dma_direction = PCI_DMA_FROMDEVICE;
pthru->numsgelements = mega_build_sglist(adapter, scb,
&pthru->dataxferaddr, &pthru->dataxferlen);
mbox->m_out.xferaddr = scb->pthru_dma_addr;
return scb;
case READ_6:
case WRITE_6:
case READ_10:
case WRITE_10:
case READ_12:
case WRITE_12:
/* Allocate a SCB and initialize mailbox */
if(!(scb = mega_allocate_scb(adapter, cmd))) {
*busy = 1;
return NULL;
}
mbox = (mbox_t *)scb->raw_mbox;
memset(mbox, 0, sizeof(scb->raw_mbox));
mbox->m_out.logdrv = ldrv_num;
/*
* A little hack: 2nd bit is zero for all scsi read
* commands and is set for all scsi write commands
*/
if( adapter->has_64bit_addr ) {
mbox->m_out.cmd = (*cmd->cmnd & 0x02) ?
MEGA_MBOXCMD_LWRITE64:
MEGA_MBOXCMD_LREAD64 ;
}
else {
mbox->m_out.cmd = (*cmd->cmnd & 0x02) ?
MEGA_MBOXCMD_LWRITE:
MEGA_MBOXCMD_LREAD ;
}
/*
* 6-byte READ(0x08) or WRITE(0x0A) cdb
*/
if( cmd->cmd_len == 6 ) {
mbox->m_out.numsectors = (u32) cmd->cmnd[4];
mbox->m_out.lba =
((u32)cmd->cmnd[1] << 16) |
((u32)cmd->cmnd[2] << 8) |
(u32)cmd->cmnd[3];
mbox->m_out.lba &= 0x1FFFFF;
#if MEGA_HAVE_STATS
/*
* Take modulo 0x80, since the logical drive
* number increases by 0x80 when a logical
* drive was deleted
*/
if (*cmd->cmnd == READ_6) {
adapter->nreads[ldrv_num%0x80]++;
adapter->nreadblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
} else {
adapter->nwrites[ldrv_num%0x80]++;
adapter->nwriteblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
}
#endif
}
/*
* 10-byte READ(0x28) or WRITE(0x2A) cdb
*/
if( cmd->cmd_len == 10 ) {
mbox->m_out.numsectors =
(u32)cmd->cmnd[8] |
((u32)cmd->cmnd[7] << 8);
mbox->m_out.lba =
((u32)cmd->cmnd[2] << 24) |
((u32)cmd->cmnd[3] << 16) |
((u32)cmd->cmnd[4] << 8) |
(u32)cmd->cmnd[5];
#if MEGA_HAVE_STATS
if (*cmd->cmnd == READ_10) {
adapter->nreads[ldrv_num%0x80]++;
adapter->nreadblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
} else {
adapter->nwrites[ldrv_num%0x80]++;
adapter->nwriteblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
}
#endif
}
/*
* 12-byte READ(0xA8) or WRITE(0xAA) cdb
*/
if( cmd->cmd_len == 12 ) {
mbox->m_out.lba =
((u32)cmd->cmnd[2] << 24) |
((u32)cmd->cmnd[3] << 16) |
((u32)cmd->cmnd[4] << 8) |
(u32)cmd->cmnd[5];
mbox->m_out.numsectors =
((u32)cmd->cmnd[6] << 24) |
((u32)cmd->cmnd[7] << 16) |
((u32)cmd->cmnd[8] << 8) |
(u32)cmd->cmnd[9];
#if MEGA_HAVE_STATS
if (*cmd->cmnd == READ_12) {
adapter->nreads[ldrv_num%0x80]++;
adapter->nreadblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
} else {
adapter->nwrites[ldrv_num%0x80]++;
adapter->nwriteblocks[ldrv_num%0x80] +=
mbox->m_out.numsectors;
}
#endif
}