📄 aachba.c
字号:
/* * Adaptec AAC series RAID controller driver * (c) Copyright 2001 Red Hat Inc. <alan@redhat.com> * * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) * * 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, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <linux/kernel.h>#include <linux/init.h>#include <linux/types.h>#include <linux/sched.h>#include <linux/pci.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/completion.h>#include <linux/blkdev.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "aacraid.h"/* values for inqd_pdt: Peripheral device type in plain English */#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */#define INQD_PDT_PROC 0x03 /* Processor device */#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask *//* * Sense codes */ #define SENCODE_NO_SENSE 0x00#define SENCODE_END_OF_DATA 0x00#define SENCODE_BECOMING_READY 0x04#define SENCODE_INIT_CMD_REQUIRED 0x04#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A#define SENCODE_INVALID_COMMAND 0x20#define SENCODE_LBA_OUT_OF_RANGE 0x21#define SENCODE_INVALID_CDB_FIELD 0x24#define SENCODE_LUN_NOT_SUPPORTED 0x25#define SENCODE_INVALID_PARAM_FIELD 0x26#define SENCODE_PARAM_NOT_SUPPORTED 0x26#define SENCODE_PARAM_VALUE_INVALID 0x26#define SENCODE_RESET_OCCURRED 0x29#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E#define SENCODE_INQUIRY_DATA_CHANGED 0x3F#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39#define SENCODE_DIAGNOSTIC_FAILURE 0x40#define SENCODE_INTERNAL_TARGET_FAILURE 0x44#define SENCODE_INVALID_MESSAGE_ERROR 0x49#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c#define SENCODE_OVERLAPPED_COMMAND 0x4E/* * Additional sense codes */ #define ASENCODE_NO_SENSE 0x00#define ASENCODE_END_OF_DATA 0x05#define ASENCODE_BECOMING_READY 0x01#define ASENCODE_INIT_CMD_REQUIRED 0x02#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00#define ASENCODE_INVALID_COMMAND 0x00#define ASENCODE_LBA_OUT_OF_RANGE 0x00#define ASENCODE_INVALID_CDB_FIELD 0x00#define ASENCODE_LUN_NOT_SUPPORTED 0x00#define ASENCODE_INVALID_PARAM_FIELD 0x00#define ASENCODE_PARAM_NOT_SUPPORTED 0x01#define ASENCODE_PARAM_VALUE_INVALID 0x02#define ASENCODE_RESET_OCCURRED 0x00#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00#define ASENCODE_INQUIRY_DATA_CHANGED 0x03#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00#define ASENCODE_DIAGNOSTIC_FAILURE 0x80#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00#define ASENCODE_INVALID_MESSAGE_ERROR 0x00#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00#define ASENCODE_OVERLAPPED_COMMAND 0x00#define BYTE0(x) (unsigned char)(x)#define BYTE1(x) (unsigned char)((x) >> 8)#define BYTE2(x) (unsigned char)((x) >> 16)#define BYTE3(x) (unsigned char)((x) >> 24)/*------------------------------------------------------------------------------ * S T R U C T S / T Y P E D E F S *----------------------------------------------------------------------------*//* SCSI inquiry data */struct inquiry_data { u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ u8 inqd_dtq; /* RMB | Device Type Qualifier */ u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ u8 inqd_len; /* Additional length (n-4) */ u8 inqd_pad1[2];/* Reserved - must be zero */ u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ u8 inqd_vid[8]; /* Vendor ID */ u8 inqd_pid[16];/* Product ID */ u8 inqd_prl[4]; /* Product Revision Level */};/* * M O D U L E G L O B A L S */ static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg);static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);#ifdef AAC_DETAILED_STATUS_INFOstatic char *aac_get_status_string(u32 status);#endif/* * Non dasd selection is handled entirely in aachba now */ static int nondasd = -1;static int dacmode = -1;static int commit = -1;module_param(nondasd, int, 0);MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");module_param(dacmode, int, 0);MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");module_param(commit, int, 0);MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on");int numacb = -1;module_param(numacb, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid\nvalues are 512 and down. Default is to use suggestion from Firmware.");int acbsize = -1;module_param(acbsize, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512,\n2048, 4096 and 8192. Default is to use suggestion from Firmware.");/** * aac_get_config_status - check the adapter configuration * @common: adapter to query * * Query config status, and commit the configuration if needed. */int aac_get_config_status(struct aac_dev *dev){ int status = 0; struct fib * fibptr; if (!(fibptr = fib_alloc(dev))) return -ENOMEM; fib_init(fibptr); { struct aac_get_config_status *dinfo; dinfo = (struct aac_get_config_status *) fib_data(fibptr); dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS); dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data)); } status = fib_send(ContainerCommand, fibptr, sizeof (struct aac_get_config_status), FsaNormal, 1, 1, NULL, NULL); if (status < 0 ) { printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n"); } else { struct aac_get_config_status_resp *reply = (struct aac_get_config_status_resp *) fib_data(fibptr); dprintk((KERN_WARNING "aac_get_config_status: response=%d status=%d action=%d\n", le32_to_cpu(reply->response), le32_to_cpu(reply->status), le32_to_cpu(reply->data.action))); if ((le32_to_cpu(reply->response) != ST_OK) || (le32_to_cpu(reply->status) != CT_OK) || (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) { printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n"); status = -EINVAL; } } fib_complete(fibptr); /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ if (status >= 0) { if (commit == 1) { struct aac_commit_config * dinfo; fib_init(fibptr); dinfo = (struct aac_commit_config *) fib_data(fibptr); dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG); status = fib_send(ContainerCommand, fibptr, sizeof (struct aac_commit_config), FsaNormal, 1, 1, NULL, NULL); fib_complete(fibptr); } else if (commit == 0) { printk(KERN_WARNING "aac_get_config_status: Foreign device configurations are being ignored\n"); } } fib_free(fibptr); return status;}/** * aac_get_containers - list containers * @common: adapter to probe * * Make a list of all containers on this controller */int aac_get_containers(struct aac_dev *dev){ struct fsa_dev_info *fsa_dev_ptr; u32 index; int status = 0; struct fib * fibptr; unsigned instance; struct aac_get_container_count *dinfo; struct aac_get_container_count_resp *dresp; int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; instance = dev->scsi_host_ptr->unique_id; if (!(fibptr = fib_alloc(dev))) return -ENOMEM; fib_init(fibptr); dinfo = (struct aac_get_container_count *) fib_data(fibptr); dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT); status = fib_send(ContainerCommand, fibptr, sizeof (struct aac_get_container_count), FsaNormal, 1, 1, NULL, NULL); if (status >= 0) { dresp = (struct aac_get_container_count_resp *)fib_data(fibptr); maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); fib_complete(fibptr); } if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) maximum_num_containers = MAXIMUM_NUM_CONTAINERS; fsa_dev_ptr = (struct fsa_dev_info *) kmalloc( sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL); if (!fsa_dev_ptr) { fib_free(fibptr); return -ENOMEM; } memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers); dev->fsa_dev = fsa_dev_ptr; dev->maximum_num_containers = maximum_num_containers; for (index = 0; index < dev->maximum_num_containers; index++) { struct aac_query_mount *dinfo; struct aac_mount *dresp; fsa_dev_ptr[index].devname[0] = '\0'; fib_init(fibptr); dinfo = (struct aac_query_mount *) fib_data(fibptr); dinfo->command = cpu_to_le32(VM_NameServe); dinfo->count = cpu_to_le32(index); dinfo->type = cpu_to_le32(FT_FILESYS); status = fib_send(ContainerCommand, fibptr, sizeof (struct aac_query_mount), FsaNormal, 1, 1, NULL, NULL); if (status < 0 ) { printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); break; } dresp = (struct aac_mount *)fib_data(fibptr); if ((le32_to_cpu(dresp->status) == ST_OK) && (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) { dinfo->command = cpu_to_le32(VM_NameServe64); dinfo->count = cpu_to_le32(index); dinfo->type = cpu_to_le32(FT_FILESYS); if (fib_send(ContainerCommand, fibptr, sizeof(struct aac_query_mount), FsaNormal, 1, 1, NULL, NULL) < 0) continue; } else dresp->mnt[0].capacityhigh = 0; dprintk ((KERN_DEBUG "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n", (int)index, (int)le32_to_cpu(dresp->status), (int)le32_to_cpu(dresp->mnt[0].vol), (int)le32_to_cpu(dresp->mnt[0].state), ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32))); if ((le32_to_cpu(dresp->status) == ST_OK) && (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { fsa_dev_ptr[index].valid = 1; fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol); fsa_dev_ptr[index].size = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) fsa_dev_ptr[index].ro = 1; } fib_complete(fibptr); /* * If there are no more containers, then stop asking. */ if ((index + 1) >= le32_to_cpu(dresp->count)){ break; } } fib_free(fibptr); return status;}static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len){ void *buf; unsigned int transfer_len; struct scatterlist *sg = scsicmd->request_buffer; if (scsicmd->use_sg) { buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; transfer_len = min(sg->length, len + offset); } else { buf = scsicmd->request_buffer; transfer_len = min(scsicmd->request_bufflen, len + offset); } memcpy(buf + offset, data, transfer_len - offset); if (scsicmd->use_sg) kunmap_atomic(buf - sg->offset, KM_IRQ0);}static void get_container_name_callback(void *context, struct fib * fibptr){ struct aac_get_name_resp * get_name_reply; struct scsi_cmnd * scsicmd; scsicmd = (struct scsi_cmnd *) context; dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); if (fibptr == NULL) BUG(); get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr); /* Failure is irrelevant, using default value instead */ if ((le32_to_cpu(get_name_reply->status) == CT_OK) && (get_name_reply->data[0] != '\0')) { char *sp = get_name_reply->data; sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; while (*sp == ' ') ++sp; if (*sp) { char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; int count = sizeof(d); char *dp = d; do { *dp++ = (*sp) ? *sp++ : ' '; } while (--count > 0); aac_internal_transfer(scsicmd, d, offsetof(struct inquiry_data, inqd_pid), sizeof(d)); } } scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; fib_complete(fibptr); fib_free(fibptr); scsicmd->scsi_done(scsicmd);}/** * aac_get_container_name - get container name, none blocking. */static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid){ int status; struct aac_get_name *dinfo; struct fib * cmd_fibcontext; struct aac_dev * dev; dev = (struct aac_dev *)scsicmd->device->host->hostdata; if (!(cmd_fibcontext = fib_alloc(dev))) return -ENOMEM; fib_init(cmd_fibcontext); dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext); dinfo->command = cpu_to_le32(VM_ContainerConfig); dinfo->type = cpu_to_le32(CT_READ_NAME); dinfo->cid = cpu_to_le32(cid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -