From 4311fa60b0d1cb5a2f62f646978294bca7b46cbb Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Thu, 22 Jun 2006 15:46:15 -0400 Subject: [SCSI] kmalloc argument switcheroo in recent 53c700 change. On Wed, Jun 21, 2006 at 07:00:34PM +0000, Linux Kernel wrote: > commit 67d59dfdeb21df2c16dcd478b66177e91178ecd0 > tree ae85703651d81740f4a6cd398f9dd4d6aabe6a2f > parent 6db874fbdbedba5e15e76cc03b42f52ea70338c0 > author James Bottomley Wed, 14 Jun 2006 07:31:19 -0500 > committer James Bottomley Tue, 20 Jun 2006 05:34:01 -0500 > > [SCSI] 53c700: remove reliance on deprecated cmnd fields > ... > > + SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense)); > + > + if (!SDp->hostdata) > + return -ENOMEM; "I'll take reversed arguments for $100 please Alex". Signed-off-by: Dave Jones Signed-off-by: James Bottomley --- drivers/scsi/53c700.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index 3c683dc2354..bff04797739 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -2044,7 +2044,7 @@ NCR_700_slave_configure(struct scsi_device *SDp) struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense)); + SDp->hostdata = kmalloc(sizeof(struct NCR_700_sense), GFP_KERNEL); if (!SDp->hostdata) return -ENOMEM; -- cgit v1.2.3 From c65b1445d153a66ca91b00c1f10187e495c17918 Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Tue, 6 Jun 2006 00:11:24 -0400 Subject: [SCSI] scsi_debug version 1.79 - add 'virtual_gb' parameter to simulate large storage (by wrapping in dev_size_mb megabytes of actual ram) - add 'no_lun_0' parameter to skip lun 0 on each target (but still respond as required to INQUIRY + REPORT LUNS) - add well know lu support - add MODE SELECT commands support [pages: 0xa and 0x1c] - add LOG SENSE command support [pages: 0xd and 0x2f] - add READ CAPACITY (16) support - increase number of mode pages supported (to read), mainly transport specific (SAS) mode (sub)pages - add more VPD pages and extend others, including ATA information VPD page - START STOP UNIT now maintains a state machine - READ (16) and WRITE (16) cope with lbas larger than 32 bits (needed for the 'virtual_gb' parameter) - allow single command transfers up to 32 MB - more precise error (sense data) messages Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 1223 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 1028 insertions(+), 195 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 5a5d2af8ee4..1da8ccde6d1 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -51,18 +51,22 @@ #include "scsi_logging.h" #include "scsi_debug.h" -#define SCSI_DEBUG_VERSION "1.75" -static const char * scsi_debug_version_date = "20050113"; +#define SCSI_DEBUG_VERSION "1.79" +static const char * scsi_debug_version_date = "20060604"; /* Additional Sense Code (ASC) used */ -#define NO_ADDED_SENSE 0x0 +#define NO_ADDITIONAL_SENSE 0x0 +#define LOGICAL_UNIT_NOT_READY 0x4 #define UNRECOVERED_READ_ERR 0x11 +#define PARAMETER_LIST_LENGTH_ERR 0x1a #define INVALID_OPCODE 0x20 #define ADDR_OUT_OF_RANGE 0x21 #define INVALID_FIELD_IN_CDB 0x24 +#define INVALID_FIELD_IN_PARAM_LIST 0x26 #define POWERON_RESET 0x29 #define SAVING_PARAMS_UNSUP 0x39 -#define THRESHHOLD_EXCEEDED 0x5d +#define THRESHOLD_EXCEEDED 0x5d +#define LOW_POWER_COND_ON 0x5e #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ @@ -81,6 +85,8 @@ static const char * scsi_debug_version_date = "20050113"; #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ #define DEF_PTYPE 0 #define DEF_D_SENSE 0 +#define DEF_NO_LUN_0 0 +#define DEF_VIRTUAL_GB 0 /* bit mask values for scsi_debug_opts */ #define SCSI_DEBUG_OPT_NOISE 1 @@ -107,6 +113,7 @@ static const char * scsi_debug_version_date = "20050113"; /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) * or "peripheral device" addressing (value 0) */ #define SAM2_LUN_ADDRESS_METHOD 0 +#define SAM2_WLUN_REPORT_LUNS 0xc101 static int scsi_debug_add_host = DEF_NUM_HOST; static int scsi_debug_delay = DEF_DELAY; @@ -119,13 +126,16 @@ static int scsi_debug_opts = DEF_OPTS; static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ static int scsi_debug_dsense = DEF_D_SENSE; +static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; +static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; static int scsi_debug_cmnd_count = 0; #define DEV_READONLY(TGT) (0) #define DEV_REMOVEABLE(TGT) (0) -static unsigned long sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_size; /* in bytes */ +static unsigned int sdebug_store_sectors; static sector_t sdebug_capacity; /* in sectors */ /* old BIOS stuff, kernel may get rid of them but some mode sense pages @@ -150,7 +160,9 @@ struct sdebug_dev_info { unsigned int target; unsigned int lun; struct sdebug_host_info *sdbg_host; + unsigned int wlun; char reset; + char stopped; char used; }; @@ -194,11 +206,11 @@ static struct scsi_host_template sdebug_driver_template = { .bios_param = scsi_debug_biosparam, .can_queue = SCSI_DEBUG_CANQUEUE, .this_id = 7, - .sg_tablesize = 64, - .cmd_per_lun = 3, - .max_sectors = 4096, + .sg_tablesize = 256, + .cmd_per_lun = 16, + .max_sectors = 0xffff, .unchecked_isa_dma = 0, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, .module = THIS_MODULE, }; @@ -226,19 +238,32 @@ static struct device_driver sdebug_driverfs_driver = { static const int check_condition_result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; +static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + 0, 0, 0x2, 0x4b}; +static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + /* function declarations */ static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, struct sdebug_dev_info * devip); static int resp_requests(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); +static int resp_start_stop(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); static int resp_readcap(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); -static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, +static int resp_readcap16(struct scsi_cmnd * SCpnt, + struct sdebug_dev_info * devip); +static int resp_mode_sense(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip); -static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip); -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip); +static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, + struct sdebug_dev_info * devip); +static int resp_log_sense(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip); +static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip); +static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip); static int resp_report_luns(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip); static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, @@ -249,8 +274,8 @@ static void timer_intr_handler(unsigned long); static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, int asc, int asq); -static int check_reset(struct scsi_cmnd * SCpnt, - struct sdebug_dev_info * devip); +static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, + struct sdebug_dev_info * devip); static int schedule_resp(struct scsi_cmnd * cmnd, struct sdebug_dev_info * devip, done_funct_t done, int scsi_result, int delta_jiff); @@ -258,8 +283,10 @@ static void __init sdebug_build_parts(unsigned char * ramp); static void __init init_all_queued(void); static void stop_all_queued(void); static int stop_queued_cmnd(struct scsi_cmnd * cmnd); -static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, - const char * dev_id_str, int dev_id_str_len); +static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, + int dev_id_num, const char * dev_id_str, + int dev_id_str_len); +static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); static void do_create_driverfs_files(void); static void do_remove_driverfs_files(void); @@ -275,18 +302,22 @@ static int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) { unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int block, upper_blk, num, k; + int len, k, j; + unsigned int num; + unsigned long long lba; int errsts = 0; - int target = scmd_id(SCpnt); + int target = SCpnt->device->id; struct sdebug_dev_info * devip = NULL; int inj_recovered = 0; + int delay_override = 0; if (done == NULL) return 0; /* assume mid level reprocessing command */ + SCpnt->resid = 0; if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { printk(KERN_INFO "scsi_debug: cmd "); - for (k = 0, num = SCpnt->cmd_len; k < num; ++k) + for (k = 0, len = SCpnt->cmd_len; k < len; ++k) printk("%02x ", (int)cmd[k]); printk("\n"); } @@ -297,7 +328,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) DID_NO_CONNECT << 16, 0); } - if (SCpnt->device->lun >= scsi_debug_max_luns) + if ((SCpnt->device->lun >= scsi_debug_max_luns) && + (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) return schedule_resp(SCpnt, NULL, done, DID_NO_CONNECT << 16, 0); devip = devInfoReg(SCpnt->device); @@ -316,118 +348,150 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) inj_recovered = 1; /* to reads and writes below */ } + if (devip->wlun) { + switch (*cmd) { + case INQUIRY: + case REQUEST_SENSE: + case TEST_UNIT_READY: + case REPORT_LUNS: + break; /* only allowable wlun commands */ + default: + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Opcode: 0x%x " + "not supported for wlun\n", *cmd); + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + return schedule_resp(SCpnt, devip, done, errsts, + 0); + } + } + switch (*cmd) { case INQUIRY: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_inquiry(SCpnt, target, devip); break; case REQUEST_SENSE: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_requests(SCpnt, devip); break; case REZERO_UNIT: /* actually this is REWIND for SSC */ case START_STOP: - errsts = check_reset(SCpnt, devip); + errsts = resp_start_stop(SCpnt, devip); break; case ALLOW_MEDIUM_REMOVAL: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 1, devip))) break; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Medium removal %s\n", cmd[4] ? "inhibited" : "enabled"); break; case SEND_DIAGNOSTIC: /* mandatory */ - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case TEST_UNIT_READY: /* mandatory */ - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); break; case RESERVE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RESERVE_10: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case RELEASE_10: - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 1, devip); break; case READ_CAPACITY: errsts = resp_readcap(SCpnt, devip); break; + case SERVICE_ACTION_IN: + if (SAI_READ_CAPACITY_16 != cmd[1]) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_OPCODE, 0); + errsts = check_condition_result; + break; + } + errsts = resp_readcap16(SCpnt, devip); + break; case READ_16: case READ_12: case READ_10: case READ_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == READ_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == READ_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == READ_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* READ (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_read(SCpnt, upper_blk, block, num, devip); + errsts = resp_read(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; case REPORT_LUNS: /* mandatory, ignore unit attention */ + delay_override = 1; errsts = resp_report_luns(SCpnt, devip); break; case VERIFY: /* 10 byte SBC-2 command */ - errsts = check_reset(SCpnt, devip); + errsts = check_readiness(SCpnt, 0, devip); break; case WRITE_16: case WRITE_12: case WRITE_10: case WRITE_6: - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 0, devip))) break; - upper_blk = 0; if ((*cmd) == WRITE_16) { - upper_blk = cmd[5] + (cmd[4] << 8) + - (cmd[3] << 16) + (cmd[2] << 24); - block = cmd[9] + (cmd[8] << 8) + - (cmd[7] << 16) + (cmd[6] << 24); + for (lba = 0, j = 0; j < 8; ++j) { + if (j > 0) + lba <<= 8; + lba += cmd[2 + j]; + } num = cmd[13] + (cmd[12] << 8) + (cmd[11] << 16) + (cmd[10] << 24); } else if ((*cmd) == WRITE_12) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); } else if ((*cmd) == WRITE_10) { - block = cmd[5] + (cmd[4] << 8) + + lba = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); num = cmd[8] + (cmd[7] << 8); - } else { - block = cmd[3] + (cmd[2] << 8) + + } else { /* WRITE (6) */ + lba = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); - num = cmd[4]; + num = (0 == cmd[4]) ? 256 : cmd[4]; } - errsts = resp_write(SCpnt, upper_blk, block, num, devip); + errsts = resp_write(SCpnt, lba, num, devip); if (inj_recovered && (0 == errsts)) { mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHHOLD_EXCEEDED, 0); + THRESHOLD_EXCEEDED, 0); errsts = check_condition_result; } break; @@ -435,20 +499,31 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) case MODE_SENSE_10: errsts = resp_mode_sense(SCpnt, target, devip); break; + case MODE_SELECT: + errsts = resp_mode_select(SCpnt, 1, devip); + break; + case MODE_SELECT_10: + errsts = resp_mode_select(SCpnt, 0, devip); + break; + case LOG_SENSE: + errsts = resp_log_sense(SCpnt, devip); + break; case SYNCHRONIZE_CACHE: - errsts = check_reset(SCpnt, devip); + delay_override = 1; + errsts = check_readiness(SCpnt, 0, devip); break; default: if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " "supported\n", *cmd); - if ((errsts = check_reset(SCpnt, devip))) + if ((errsts = check_readiness(SCpnt, 1, devip))) break; /* Unit attention takes precedence */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); errsts = check_condition_result; break; } - return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay); + return schedule_resp(SCpnt, devip, done, errsts, + (delay_override ? 0 : scsi_debug_delay)); } static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) @@ -460,7 +535,8 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) /* return -ENOTTY; // correct return but upsets fdisk */ } -static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) +static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, + struct sdebug_dev_info * devip) { if (devip->reset) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) @@ -470,6 +546,14 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); return check_condition_result; } + if ((0 == reset_only) && devip->stopped) { + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + printk(KERN_INFO "scsi_debug: Reporting Not " + "ready: initializing command required\n"); + mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, + 0x2); + return check_condition_result; + } return 0; } @@ -493,7 +577,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, req_len = scp->request_bufflen; act_len = (req_len < arr_len) ? req_len : arr_len; memcpy(scp->request_buffer, arr, act_len); - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } sgpnt = (struct scatterlist *)scp->request_buffer; @@ -516,7 +603,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, } req_len += sgpnt->length; } - scp->resid = req_len - act_len; + if (scp->resid) + scp->resid -= act_len; + else + scp->resid = req_len - act_len; return 0; } @@ -567,12 +657,14 @@ static const char * inq_vendor_id = "Linux "; static const char * inq_product_id = "scsi_debug "; static const char * inq_product_rev = "0004"; -static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, - const char * dev_id_str, int dev_id_str_len) +static int inquiry_evpd_83(unsigned char * arr, int target_dev_id, + int dev_id_num, const char * dev_id_str, + int dev_id_str_len) { - int num; + int num, port_a; + char b[32]; - /* Two identification descriptors: */ + port_a = target_dev_id + 1; /* T10 vendor identifier field format (faked) */ arr[0] = 0x2; /* ASCII */ arr[1] = 0x1; @@ -583,25 +675,246 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, num = 8 + 16 + dev_id_str_len; arr[3] = num; num += 4; - /* NAA IEEE registered identifier (faked) */ - arr[num] = 0x1; /* binary */ - arr[num + 1] = 0x3; - arr[num + 2] = 0x0; - arr[num + 3] = 0x8; - arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ - arr[num + 5] = 0x23; - arr[num + 6] = 0x45; - arr[num + 7] = 0x60; - arr[num + 8] = (dev_id_num >> 24); - arr[num + 9] = (dev_id_num >> 16) & 0xff; - arr[num + 10] = (dev_id_num >> 8) & 0xff; - arr[num + 11] = dev_id_num & 0xff; - return num + 12; + if (dev_id_num >= 0) { + /* NAA-5, Logical unit identifier (binary) */ + arr[num++] = 0x1; /* binary (not necessarily sas) */ + arr[num++] = 0x3; /* PIV=0, lu, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ + arr[num++] = 0x33; + arr[num++] = 0x33; + arr[num++] = 0x30; + arr[num++] = (dev_id_num >> 24); + arr[num++] = (dev_id_num >> 16) & 0xff; + arr[num++] = (dev_id_num >> 8) & 0xff; + arr[num++] = dev_id_num & 0xff; + /* Target relative port number */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x94; /* PIV=1, target port, rel port */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x4; /* length */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port A */ + } + /* NAA-5, Target port identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* piv=1, target port, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + /* NAA-5, Target device identifier */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0xa3; /* piv=1, target device, naa */ + arr[num++] = 0x0; + arr[num++] = 0x8; + arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (target_dev_id >> 24); + arr[num++] = (target_dev_id >> 16) & 0xff; + arr[num++] = (target_dev_id >> 8) & 0xff; + arr[num++] = target_dev_id & 0xff; + /* SCSI name string: Target device identifier */ + arr[num++] = 0x63; /* proto=sas, UTF-8 */ + arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ + arr[num++] = 0x0; + arr[num++] = 24; + memcpy(arr + num, "naa.52222220", 12); + num += 12; + snprintf(b, sizeof(b), "%08X", target_dev_id); + memcpy(arr + num, b, 8); + num += 8; + memset(arr + num, 0, 4); + num += 4; + return num; +} + + +static unsigned char vpd84_data[] = { +/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, + 0x22,0x22,0x22,0x0,0xbb,0x1, + 0x22,0x22,0x22,0x0,0xbb,0x2, +}; + +static int inquiry_evpd_84(unsigned char * arr) +{ + memcpy(arr, vpd84_data, sizeof(vpd84_data)); + return sizeof(vpd84_data); +} + +static int inquiry_evpd_85(unsigned char * arr) +{ + int num = 0; + const char * na1 = "https://www.kernel.org/config"; + const char * na2 = "http://www.kernel.org/log"; + int plen, olen; + + arr[num++] = 0x1; /* lu, storage config */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na1); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null termianted, padded */ + memcpy(arr + num, na1, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + arr[num++] = 0x4; /* lu, logging */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + olen = strlen(na2); + plen = olen + 1; + if (plen % 4) + plen = ((plen / 4) + 1) * 4; + arr[num++] = plen; /* length, null terminated, padded */ + memcpy(arr + num, na2, olen); + memset(arr + num + olen, 0, plen - olen); + num += plen; + + return num; +} + +/* SCSI ports VPD page */ +static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) +{ + int num = 0; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x1; /* relative port 1 (primary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (A) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_a >> 24); + arr[num++] = (port_a >> 16) & 0xff; + arr[num++] = (port_a >> 8) & 0xff; + arr[num++] = port_a & 0xff; + + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x0; + arr[num++] = 0x2; /* relative port 2 (secondary) */ + memset(arr + num, 0, 6); + num += 6; + arr[num++] = 0x0; + arr[num++] = 12; /* length tp descriptor */ + /* naa-5 target port identifier (B) */ + arr[num++] = 0x61; /* proto=sas, binary */ + arr[num++] = 0x93; /* PIV=1, target port, NAA */ + arr[num++] = 0x0; /* reserved */ + arr[num++] = 0x8; /* length */ + arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ + arr[num++] = 0x22; + arr[num++] = 0x22; + arr[num++] = 0x20; + arr[num++] = (port_b >> 24); + arr[num++] = (port_b >> 16) & 0xff; + arr[num++] = (port_b >> 8) & 0xff; + arr[num++] = port_b & 0xff; + + return num; +} + + +static unsigned char vpd89_data[] = { +/* from 4th byte */ 0,0,0,0, +'l','i','n','u','x',' ',' ',' ', +'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', +'1','2','3','4', +0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +0xec,0,0,0, +0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, +0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, +0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, +0x53,0x41, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x20,0x20, +0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +0x10,0x80, +0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, +0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, +0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, +0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, +0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, +0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, +0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, +0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, +0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, +}; + +static int inquiry_evpd_89(unsigned char * arr) +{ + memcpy(arr, vpd89_data, sizeof(vpd89_data)); + return sizeof(vpd89_data); +} + + +static unsigned char vpdb0_data[] = { + /* from 4th byte */ 0,0,0,4, + 0,0,0x4,0, + 0,0,0,64, +}; + +static int inquiry_evpd_b0(unsigned char * arr) +{ + memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); + if (sdebug_store_sectors > 0x400) { + arr[4] = (sdebug_store_sectors >> 24) & 0xff; + arr[5] = (sdebug_store_sectors >> 16) & 0xff; + arr[6] = (sdebug_store_sectors >> 8) & 0xff; + arr[7] = sdebug_store_sectors & 0xff; + } + return sizeof(vpdb0_data); } #define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 128 +#define SDEBUG_MAX_INQ_ARR_SZ 584 static int resp_inquiry(struct scsi_cmnd * scp, int target, struct sdebug_dev_info * devip) @@ -609,64 +922,113 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target, unsigned char pq_pdt; unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len; + int alloc_len, n; alloc_len = (cmd[3] << 8) + cmd[4]; memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); - pq_pdt = (scsi_debug_ptype & 0x1f); + if (devip->wlun) + pq_pdt = 0x1e; /* present, wlun */ + else if (scsi_debug_no_lun_0 && (0 == devip->lun)) + pq_pdt = 0x7f; /* not present, no device type */ + else + pq_pdt = (scsi_debug_ptype & 0x1f); arr[0] = pq_pdt; if (0x2 & cmd[1]) { /* CMDDT bit set */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int dev_id_num, len; - char dev_id_str[6]; + int lu_id_num, target_dev_id, len; + char lu_id_str[6]; + int host_no = devip->sdbg_host->shost->host_no; - dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) + - (devip->target * 1000) + devip->lun; - len = scnprintf(dev_id_str, 6, "%d", dev_id_num); + lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + + (devip->target * 1000) + devip->lun); + target_dev_id = ((host_no + 1) * 2000) + + (devip->target * 1000) - 3; + len = scnprintf(lu_id_str, 6, "%d", lu_id_num); if (0 == cmd[2]) { /* supported vital product data pages */ - arr[3] = 3; - arr[4] = 0x0; /* this page */ - arr[5] = 0x80; /* unit serial number */ - arr[6] = 0x83; /* device identification */ + arr[1] = cmd[2]; /*sanity */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0x80; /* unit serial number */ + arr[n++] = 0x83; /* device identification */ + arr[n++] = 0x84; /* software interface ident. */ + arr[n++] = 0x85; /* management network addresses */ + arr[n++] = 0x86; /* extended inquiry */ + arr[n++] = 0x87; /* mode page policy */ + arr[n++] = 0x88; /* SCSI ports */ + arr[n++] = 0x89; /* ATA information */ + arr[n++] = 0xb0; /* Block limits (SBC) */ + arr[3] = n - 4; /* number of supported VPD pages */ } else if (0x80 == cmd[2]) { /* unit serial number */ - arr[1] = 0x80; + arr[1] = cmd[2]; /*sanity */ arr[3] = len; - memcpy(&arr[4], dev_id_str, len); + memcpy(&arr[4], lu_id_str, len); } else if (0x83 == cmd[2]) { /* device identification */ - arr[1] = 0x83; - arr[3] = inquiry_evpd_83(&arr[4], dev_id_num, - dev_id_str, len); + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_83(&arr[4], target_dev_id, + lu_id_num, lu_id_str, len); + } else if (0x84 == cmd[2]) { /* Software interface ident. */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_84(&arr[4]); + } else if (0x85 == cmd[2]) { /* Management network addresses */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_85(&arr[4]); + } else if (0x86 == cmd[2]) { /* extended inquiry */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x3c; /* number of following entries */ + arr[4] = 0x0; /* no protection stuff */ + arr[5] = 0x7; /* head of q, ordered + simple q's */ + } else if (0x87 == cmd[2]) { /* mode page policy */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = 0x8; /* number of following entries */ + arr[4] = 0x2; /* disconnect-reconnect mp */ + arr[6] = 0x80; /* mlus, shared */ + arr[8] = 0x18; /* protocol specific lu */ + arr[10] = 0x82; /* mlus, per initiator port */ + } else if (0x88 == cmd[2]) { /* SCSI Ports */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); + } else if (0x89 == cmd[2]) { /* ATA information */ + arr[1] = cmd[2]; /*sanity */ + n = inquiry_evpd_89(&arr[4]); + arr[2] = (n >> 8); + arr[3] = (n & 0xff); + } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ + arr[1] = cmd[2]; /*sanity */ + arr[3] = inquiry_evpd_b0(&arr[4]); } else { /* Illegal request, invalid field in cdb */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); return fill_from_dev_buffer(scp, arr, - min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); + min(len, SDEBUG_MAX_INQ_ARR_SZ)); } /* drops through here for a standard inquiry */ arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ arr[2] = scsi_debug_scsi_level; arr[3] = 2; /* response_data_format==2 */ arr[4] = SDEBUG_LONG_INQ_SZ - 5; - arr[6] = 0x1; /* claim: ADDR16 */ + arr[6] = 0x10; /* claim: MultiP */ /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ - arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ + arr[7] = 0xa; /* claim: LINKED + CMDQUE */ memcpy(&arr[8], inq_vendor_id, 8); memcpy(&arr[16], inq_product_id, 16); memcpy(&arr[32], inq_product_rev, 4); /* version descriptors (2 bytes each) follow */ - arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ - arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ + arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ + arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ + n = 62; if (scsi_debug_ptype == 0) { - arr[62] = 0x1; arr[63] = 0x80; /* SBC */ + arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ } else if (scsi_debug_ptype == 1) { - arr[62] = 0x2; arr[63] = 0x00; /* SSC */ + arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ } + arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ return fill_from_dev_buffer(scp, arr, min(alloc_len, SDEBUG_LONG_INQ_SZ)); } @@ -677,46 +1039,141 @@ static int resp_requests(struct scsi_cmnd * scp, unsigned char * sbuff; unsigned char *cmd = (unsigned char *)scp->cmnd; unsigned char arr[SDEBUG_SENSE_LEN]; + int want_dsense; int len = 18; - memset(arr, 0, SDEBUG_SENSE_LEN); + memset(arr, 0, sizeof(arr)); if (devip->reset == 1) - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); + want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; sbuff = devip->sense_buff; - if ((cmd[1] & 1) && (! scsi_debug_dsense)) { - /* DESC bit set and sense_buff in fixed format */ - arr[0] = 0x72; - arr[1] = sbuff[2]; /* sense key */ - arr[2] = sbuff[12]; /* asc */ - arr[3] = sbuff[13]; /* ascq */ - len = 8; - } else + if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = THRESHOLD_EXCEEDED; + arr[3] = 0xff; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = THRESHOLD_EXCEEDED; + arr[13] = 0xff; /* TEST set and MRIE==6 */ + } + } else if (devip->stopped) { + if (want_dsense) { + arr[0] = 0x72; + arr[1] = 0x0; /* NO_SENSE in sense_key */ + arr[2] = LOW_POWER_COND_ON; + arr[3] = 0x0; /* TEST set and MRIE==6 */ + } else { + arr[0] = 0x70; + arr[2] = 0x0; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = LOW_POWER_COND_ON; + arr[13] = 0x0; /* TEST set and MRIE==6 */ + } + } else { memcpy(arr, sbuff, SDEBUG_SENSE_LEN); - mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); + if ((cmd[1] & 1) && (! scsi_debug_dsense)) { + /* DESC bit set and sense_buff in fixed format */ + memset(arr, 0, sizeof(arr)); + arr[0] = 0x72; + arr[1] = sbuff[2]; /* sense key */ + arr[2] = sbuff[12]; /* asc */ + arr[3] = sbuff[13]; /* ascq */ + len = 8; + } + } + mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); return fill_from_dev_buffer(scp, arr, len); } +static int resp_start_stop(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + int power_cond, errsts, start; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + power_cond = (cmd[4] & 0xf0) >> 4; + if (power_cond) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } + start = cmd[4] & 1; + if (start == devip->stopped) + devip->stopped = !start; + return 0; +} + #define SDEBUG_READCAP_ARR_SZ 8 static int resp_readcap(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned char arr[SDEBUG_READCAP_ARR_SZ]; - unsigned long capac; + unsigned int capac; int errsts; - if ((errsts = check_reset(scp, devip))) + if ((errsts = check_readiness(scp, 1, devip))) return errsts; + /* following just in case virtual_gb changed */ + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; memset(arr, 0, SDEBUG_READCAP_ARR_SZ); - capac = (unsigned long)sdebug_capacity - 1; - arr[0] = (capac >> 24); - arr[1] = (capac >> 16) & 0xff; - arr[2] = (capac >> 8) & 0xff; - arr[3] = capac & 0xff; + if (sdebug_capacity < 0xffffffff) { + capac = (unsigned int)sdebug_capacity - 1; + arr[0] = (capac >> 24); + arr[1] = (capac >> 16) & 0xff; + arr[2] = (capac >> 8) & 0xff; + arr[3] = capac & 0xff; + } else { + arr[0] = 0xff; + arr[1] = 0xff; + arr[2] = 0xff; + arr[3] = 0xff; + } arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; arr[7] = SECT_SIZE_PER(target) & 0xff; return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); } +#define SDEBUG_READCAP16_ARR_SZ 32 +static int resp_readcap16(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + unsigned char *cmd = (unsigned char *)scp->cmnd; + unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; + unsigned long long capac; + int errsts, k, alloc_len; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) + + cmd[13]); + /* following just in case virtual_gb changed */ + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; + memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); + capac = sdebug_capacity - 1; + for (k = 0; k < 8; ++k, capac >>= 8) + arr[7 - k] = capac & 0xff; + arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; + arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; + arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; + arr[11] = SECT_SIZE_PER(target) & 0xff; + return fill_from_dev_buffer(scp, arr, + min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); +} + /* <> */ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) @@ -772,27 +1229,98 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target) static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) { /* Control mode page for mode_sense */ - unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, + unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; + unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0x2, 0x4b}; if (scsi_debug_dsense) ctrl_m_pg[2] |= 0x4; + else + ctrl_m_pg[2] &= ~0x4; memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); + memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); return sizeof(ctrl_m_pg); } + static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) { /* Informational Exceptions control mode page for mode_sense */ - unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; + unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0x0}; + memcpy(p, iec_m_pg, sizeof(iec_m_pg)); if (1 == pcontrol) - memset(p + 2, 0, sizeof(iec_m_pg) - 2); + memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); + else if (2 == pcontrol) + memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); return sizeof(iec_m_pg); } +static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) +{ /* SAS SSP mode page - short format for mode_sense */ + unsigned char sas_sf_m_pg[] = {0x19, 0x6, + 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; + + memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); + if (1 == pcontrol) + memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); + return sizeof(sas_sf_m_pg); +} + + +static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, + int target_dev_id) +{ /* SAS phy control and discover mode page for mode_sense */ + unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, + 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x2, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, + 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, + 0x3, 0, 0, 0, 0, 0, 0, 0, + 0x88, 0x99, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + int port_a, port_b; + + port_a = target_dev_id + 1; + port_b = port_a + 1; + memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); + p[20] = (port_a >> 24); + p[21] = (port_a >> 16) & 0xff; + p[22] = (port_a >> 8) & 0xff; + p[23] = port_a & 0xff; + p[48 + 20] = (port_b >> 24); + p[48 + 21] = (port_b >> 16) & 0xff; + p[48 + 22] = (port_b >> 8) & 0xff; + p[48 + 23] = port_b & 0xff; + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); + return sizeof(sas_pcd_m_pg); +} + +static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) +{ /* SAS SSP shared protocol specific port mode subpage */ + unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); + if (1 == pcontrol) + memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); + return sizeof(sas_sha_m_pg); +} + #define SDEBUG_MAX_MSENSE_SZ 256 static int resp_mode_sense(struct scsi_cmnd * scp, int target, @@ -801,12 +1329,12 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, unsigned char dbd; int pcontrol, pcode, subpcode; unsigned char dev_spec; - int alloc_len, msense_6, offset, len, errsts; + int alloc_len, msense_6, offset, len, errsts, target_dev_id; unsigned char * ap; unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; unsigned char *cmd = (unsigned char *)scp->cmnd; - if ((errsts = check_reset(scp, devip))) + if ((errsts = check_readiness(scp, 1, devip))) return errsts; dbd = cmd[1] & 0x8; pcontrol = (cmd[2] & 0xc0) >> 6; @@ -820,6 +1348,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, 0); return check_condition_result; } + target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + + (devip->target * 1000) - 3; dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; if (msense_6) { arr[2] = dev_spec; @@ -830,7 +1360,8 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, } ap = arr + offset; - if (0 != subpcode) { /* TODO: Control Extension page */ + if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { + /* TODO: Control Extension page */ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -856,17 +1387,45 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, len = resp_ctrl_m_pg(ap, pcontrol, target); offset += len; break; + case 0x19: /* if spc==1 then sas phy, control+discover */ + if ((subpcode > 0x2) && (subpcode < 0xff)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = 0; + if ((0x0 == subpcode) || (0xff == subpcode)) + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if ((0x1 == subpcode) || (0xff == subpcode)) + len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, + target_dev_id); + if ((0x2 == subpcode) || (0xff == subpcode)) + len += resp_sas_sha_m_spg(ap + len, pcontrol); + offset += len; + break; case 0x1c: /* Informational Exceptions Mode page, all devices */ len = resp_iec_m_pg(ap, pcontrol, target); offset += len; break; case 0x3f: /* Read all Mode pages */ - len = resp_err_recov_pg(ap, pcontrol, target); - len += resp_disconnect_pg(ap + len, pcontrol, target); - len += resp_format_pg(ap + len, pcontrol, target); - len += resp_caching_pg(ap + len, pcontrol, target); - len += resp_ctrl_m_pg(ap + len, pcontrol, target); - len += resp_iec_m_pg(ap + len, pcontrol, target); + if ((0 == subpcode) || (0xff == subpcode)) { + len = resp_err_recov_pg(ap, pcontrol, target); + len += resp_disconnect_pg(ap + len, pcontrol, target); + len += resp_format_pg(ap + len, pcontrol, target); + len += resp_caching_pg(ap + len, pcontrol, target); + len += resp_ctrl_m_pg(ap + len, pcontrol, target); + len += resp_sas_sf_m_pg(ap + len, pcontrol, target); + if (0xff == subpcode) { + len += resp_sas_pcd_m_spg(ap + len, pcontrol, + target, target_dev_id); + len += resp_sas_sha_m_spg(ap + len, pcontrol); + } + len += resp_iec_m_pg(ap + len, pcontrol, target); + } else { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } offset += len; break; default: @@ -883,71 +1442,274 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target, return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); } -static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip) +#define SDEBUG_MAX_MSELECT_SZ 512 + +static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, + struct sdebug_dev_info * devip) +{ + int pf, sp, ps, md_len, bd_len, off, spf, pg_len; + int param_len, res, errsts, mpage; + unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + pf = cmd[1] & 0x10; + sp = cmd[1] & 0x1; + param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); + if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + res = fetch_to_dev_buffer(scp, arr, param_len); + if (-1 == res) + return (DID_ERROR << 16); + else if ((res < param_len) && + (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) + printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " + " IO sent=%d bytes\n", param_len, res); + md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); + bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); + if ((md_len > 2) || (0 != bd_len)) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + off = bd_len + (mselect6 ? 4 : 8); + mpage = arr[off] & 0x3f; + ps = !!(arr[off] & 0x80); + if (ps) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; + } + spf = !!(arr[off] & 0x40); + pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : + (arr[off + 1] + 2); + if ((pg_len + off) > param_len) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + PARAMETER_LIST_LENGTH_ERR, 0); + return check_condition_result; + } + switch (mpage) { + case 0xa: /* Control Mode page */ + if (ctrl_m_pg[1] == arr[off + 1]) { + memcpy(ctrl_m_pg + 2, arr + off + 2, + sizeof(ctrl_m_pg) - 2); + scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); + return 0; + } + break; + case 0x1c: /* Informational Exceptions Mode page */ + if (iec_m_pg[1] == arr[off + 1]) { + memcpy(iec_m_pg + 2, arr + off + 2, + sizeof(iec_m_pg) - 2); + return 0; + } + break; + default: + break; + } + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_PARAM_LIST, 0); + return check_condition_result; +} + +static int resp_temp_l_pg(unsigned char * arr) +{ + unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, + 0x0, 0x1, 0x3, 0x2, 0x0, 65, + }; + + memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); + return sizeof(temp_l_pg); +} + +static int resp_ie_l_pg(unsigned char * arr) +{ + unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, + }; + + memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); + if (iec_m_pg[2] & 0x4) { /* TEST bit set */ + arr[4] = THRESHOLD_EXCEEDED; + arr[5] = 0xff; + } + return sizeof(ie_l_pg); +} + +#define SDEBUG_MAX_LSENSE_SZ 512 + +static int resp_log_sense(struct scsi_cmnd * scp, + struct sdebug_dev_info * devip) +{ + int ppc, sp, pcontrol, pcode, alloc_len, errsts, len, n; + unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; + unsigned char *cmd = (unsigned char *)scp->cmnd; + + if ((errsts = check_readiness(scp, 1, devip))) + return errsts; + memset(arr, 0, sizeof(arr)); + ppc = cmd[1] & 0x2; + sp = cmd[1] & 0x1; + if (ppc || sp) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + pcontrol = (cmd[2] & 0xc0) >> 6; + pcode = cmd[2] & 0x3f; + alloc_len = (cmd[7] << 8) + cmd[8]; + arr[0] = pcode; + switch (pcode) { + case 0x0: /* Supported log pages log page */ + n = 4; + arr[n++] = 0x0; /* this page */ + arr[n++] = 0xd; /* Temperature */ + arr[n++] = 0x2f; /* Informational exceptions */ + arr[3] = n - 4; + break; + case 0xd: /* Temperature log page */ + arr[3] = resp_temp_l_pg(arr + 4); + break; + case 0x2f: /* Informational exceptions log page */ + arr[3] = resp_ie_l_pg(arr + 4); + break; + default: + mk_sense_buffer(devip, ILLEGAL_REQUEST, + INVALID_FIELD_IN_CDB, 0); + return check_condition_result; + } + len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); + return fill_from_dev_buffer(scp, arr, + min(len, SDEBUG_MAX_INQ_ARR_SZ)); +} + +static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip) { unsigned long iflags; + unsigned int block, from_bottom; + unsigned long long u; int ret; - if (upper_blk || (block + num > sdebug_capacity)) { + if (lba + num > sdebug_capacity) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } + /* transfer length excessive (tie in to block limits VPD page) */ + if (num > sdebug_store_sectors) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && - (block <= OPT_MEDIUM_ERR_ADDR) && - ((block + num) > OPT_MEDIUM_ERR_ADDR)) { + (lba <= OPT_MEDIUM_ERR_ADDR) && + ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { + /* claim unrecoverable read error */ mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); - /* claim unrecoverable read error */ + /* set info field and valid bit for fixed descriptor */ + if (0x70 == (devip->sense_buff[0] & 0x7f)) { + devip->sense_buff[0] |= 0x80; /* Valid bit */ + ret = OPT_MEDIUM_ERR_ADDR; + devip->sense_buff[3] = (ret >> 24) & 0xff; + devip->sense_buff[4] = (ret >> 16) & 0xff; + devip->sense_buff[5] = (ret >> 8) & 0xff; + devip->sense_buff[6] = ret & 0xff; + } return check_condition_result; } read_lock_irqsave(&atomic_rw, iflags); - ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + if ((lba + num) <= sdebug_store_sectors) + ret = fill_from_dev_buffer(SCpnt, + fake_storep + (lba * SECT_SIZE), + num * SECT_SIZE); + else { + /* modulo when one arg is 64 bits needs do_div() */ + u = lba; + block = do_div(u, sdebug_store_sectors); + from_bottom = 0; + if ((block + num) > sdebug_store_sectors) + from_bottom = (block + num) - sdebug_store_sectors; + ret = fill_from_dev_buffer(SCpnt, + fake_storep + (block * SECT_SIZE), + (num - from_bottom) * SECT_SIZE); + if ((0 == ret) && (from_bottom > 0)) + ret = fill_from_dev_buffer(SCpnt, fake_storep, + from_bottom * SECT_SIZE); + } read_unlock_irqrestore(&atomic_rw, iflags); return ret; } -static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, - int num, struct sdebug_dev_info * devip) +static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, + unsigned int num, struct sdebug_dev_info * devip) { unsigned long iflags; + unsigned int block, to_bottom; + unsigned long long u; int res; - if (upper_blk || (block + num > sdebug_capacity)) { + if (lba + num > sdebug_capacity) { mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); return check_condition_result; } + /* transfer length excessive (tie in to block limits VPD page) */ + if (num > sdebug_store_sectors) { + mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, + 0); + return check_condition_result; + } write_lock_irqsave(&atomic_rw, iflags); - res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), - num * SECT_SIZE); + if ((lba + num) <= sdebug_store_sectors) + res = fetch_to_dev_buffer(SCpnt, + fake_storep + (lba * SECT_SIZE), + num * SECT_SIZE); + else { + /* modulo when one arg is 64 bits needs do_div() */ + u = lba; + block = do_div(u, sdebug_store_sectors); + to_bottom = 0; + if ((block + num) > sdebug_store_sectors) + to_bottom = (block + num) - sdebug_store_sectors; + res = fetch_to_dev_buffer(SCpnt, + fake_storep + (block * SECT_SIZE), + (num - to_bottom) * SECT_SIZE); + if ((0 == res) && (to_bottom > 0)) + res = fetch_to_dev_buffer(SCpnt, fake_storep, + to_bottom * SECT_SIZE); + } write_unlock_irqrestore(&atomic_rw, iflags); if (-1 == res) return (DID_ERROR << 16); else if ((res < (num * SECT_SIZE)) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " + printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " " IO sent=%d bytes\n", num * SECT_SIZE, res); return 0; } -#define SDEBUG_RLUN_ARR_SZ 128 +#define SDEBUG_RLUN_ARR_SZ 256 static int resp_report_luns(struct scsi_cmnd * scp, struct sdebug_dev_info * devip) { unsigned int alloc_len; - int lun_cnt, i, upper; + int lun_cnt, i, upper, num, n, wlun, lun; unsigned char *cmd = (unsigned char *)scp->cmnd; int select_report = (int)cmd[2]; struct scsi_lun *one_lun; unsigned char arr[SDEBUG_RLUN_ARR_SZ]; + unsigned char * max_addr; alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); - if ((alloc_len < 16) || (select_report > 2)) { + if ((alloc_len < 4) || (select_report > 2)) { mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); return check_condition_result; @@ -955,18 +1717,37 @@ static int resp_report_luns(struct scsi_cmnd * scp, /* can produce response with up to 16k luns (lun 0 to lun 16383) */ memset(arr, 0, SDEBUG_RLUN_ARR_SZ); lun_cnt = scsi_debug_max_luns; - arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; - arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; - lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / - sizeof(struct scsi_lun)), lun_cnt); + if (1 == select_report) + lun_cnt = 0; + else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) + --lun_cnt; + wlun = (select_report > 0) ? 1 : 0; + num = lun_cnt + wlun; + arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; + arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; + n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / + sizeof(struct scsi_lun)), num); + if (n < num) { + wlun = 0; + lun_cnt = n; + } one_lun = (struct scsi_lun *) &arr[8]; - for (i = 0; i < lun_cnt; i++) { - upper = (i >> 8) & 0x3f; + max_addr = arr + SDEBUG_RLUN_ARR_SZ; + for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); + ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); + i++, lun++) { + upper = (lun >> 8) & 0x3f; if (upper) one_lun[i].scsi_lun[0] = (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); - one_lun[i].scsi_lun[1] = i & 0xff; + one_lun[i].scsi_lun[1] = lun & 0xff; + } + if (wlun) { + one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; + one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; + i++; } + alloc_len = (unsigned char *)(one_lun + i) - arr; return fill_from_dev_buffer(scp, arr, min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); } @@ -1002,7 +1783,8 @@ static void timer_intr_handler(unsigned long indx) static int scsi_debug_slave_alloc(struct scsi_device * sdp) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_alloc\n"); + printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); return 0; } @@ -1011,7 +1793,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) struct sdebug_dev_info * devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_configure\n"); + printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; devip = devInfoReg(sdp); @@ -1019,6 +1802,7 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp) if (sdp->host->cmd_per_lun) scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, sdp->host->cmd_per_lun); + blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); return 0; } @@ -1028,7 +1812,8 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp) (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_destroy\n"); + printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", + sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (devip) { /* make this slot avaliable for re-use */ devip->used = 0; @@ -1085,6 +1870,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) open_devip->sense_buff[0] = 0x70; open_devip->sense_buff[7] = 0xa; } + if (sdev->lun == SAM2_WLUN_REPORT_LUNS) + open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; return open_devip; } return NULL; @@ -1273,7 +2060,7 @@ static void __init sdebug_build_parts(unsigned char * ramp) printk(KERN_WARNING "scsi_debug:build_parts: reducing " "partitions to %d\n", SDEBUG_MAX_PARTS); } - num_sectors = (int)(sdebug_store_size / SECT_SIZE); + num_sectors = (int)sdebug_store_sectors; sectors_per_part = (num_sectors - sdebug_sectors_per) / scsi_debug_num_parts; heads_by_sects = sdebug_heads * sdebug_sectors_per; @@ -1316,9 +2103,9 @@ static int schedule_resp(struct scsi_cmnd * cmnd, if (scsi_result) { struct scsi_device * sdp = cmnd->device; - sdev_printk(KERN_INFO, sdp, - "non-zero result=0x%x\n", - scsi_result); + printk(KERN_INFO "scsi_debug: <%u %u %u %u> " + "non-zero result=0x%x\n", sdp->host->host_no, + sdp->channel, sdp->id, sdp->lun, scsi_result); } } if (cmnd && devip) { @@ -1365,21 +2152,19 @@ static int schedule_resp(struct scsi_cmnd * cmnd, } } -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly below. - */ -module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */ -module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */ -module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0); -module_param_named(dsense, scsi_debug_dsense, int, 0); -module_param_named(every_nth, scsi_debug_every_nth, int, 0); -module_param_named(max_luns, scsi_debug_max_luns, int, 0); -module_param_named(num_parts, scsi_debug_num_parts, int, 0); -module_param_named(num_tgts, scsi_debug_num_tgts, int, 0); -module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */ -module_param_named(ptype, scsi_debug_ptype, int, 0); -module_param_named(scsi_level, scsi_debug_scsi_level, int, 0); +module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); +module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); +module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); +module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); +module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); +module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); +module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); +module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); +module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); +module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); +module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); +module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); +module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); MODULE_DESCRIPTION("SCSI debug adapter driver"); @@ -1388,15 +2173,17 @@ MODULE_VERSION(SCSI_DEBUG_VERSION); MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); -MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs"); -MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)"); +MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); +MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); -MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate"); +MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); +MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); -MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); -MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); +MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); +MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)"); MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); +MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); static char sdebug_info[256]; @@ -1548,6 +2335,24 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp, DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, sdebug_dsense_store); +static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); +} +static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_no_lun_0 = n; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, + sdebug_no_lun_0_store); + static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); @@ -1623,6 +2428,29 @@ static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) } DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); +static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); +} +static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, + const char * buf, size_t count) +{ + int n; + + if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { + scsi_debug_virtual_gb = n; + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; + return count; + } + return -EINVAL; +} +DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, + sdebug_virtual_gb_store); + static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); @@ -1692,14 +2520,19 @@ static void do_remove_driverfs_files(void) static int __init scsi_debug_init(void) { - unsigned long sz; + unsigned int sz; int host_to_add; int k; if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ - sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576; - sdebug_capacity = sdebug_store_size / SECT_SIZE; + sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; + sdebug_store_sectors = sdebug_store_size / SECT_SIZE; + if (scsi_debug_virtual_gb > 0) { + sdebug_capacity = 2048 * 1024; + sdebug_capacity *= scsi_debug_virtual_gb; + } else + sdebug_capacity = sdebug_store_sectors; /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; @@ -1813,7 +2646,7 @@ static int sdebug_add_adapter(void) struct sdebug_dev_info *sdbg_devinfo; struct list_head *lh, *lh_sf; - sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); + sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { printk(KERN_ERR "%s: out of memory at line %d\n", @@ -1825,7 +2658,7 @@ static int sdebug_add_adapter(void) devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; for (k = 0; k < devs_per_host; k++) { - sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo), GFP_KERNEL); + sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); if (NULL == sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); @@ -1906,7 +2739,7 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { @@ -1960,7 +2793,7 @@ static void sdebug_max_tgts_luns(void) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = scsi_debug_max_luns; + hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ } spin_unlock(&sdebug_host_list_lock); } -- cgit v1.2.3 From cefbda2d6cd9bf78a93768130729a6d142588d67 Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 12 Jun 2006 21:22:51 -0500 Subject: [SCSI] ibmvscsi: treat busy and error conditions separately This patch fixes a condition where ibmvscsi treats a transport error as a "busy" condition, so no errors were returned to the scsi mid-layer. In a RAID environment this means that I/O hung rather than failing over. Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 64 ++++++++++++++++++++++++++++++--------- drivers/scsi/ibmvscsi/rpa_vscsi.c | 5 +-- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 944fc1203eb..669ea4fff16 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -535,6 +535,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, struct ibmvscsi_host_data *hostdata) { u64 *crq_as_u64 = (u64 *) &evt_struct->crq; + int request_status; int rc; /* If we have exhausted our request limit, just fail this request. @@ -542,9 +543,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, * (such as task management requests) that the mid layer may think we * can handle more requests (can_queue) when we actually can't */ - if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) && - (atomic_dec_if_positive(&hostdata->request_limit) < 0)) - goto send_error; + if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) { + request_status = + atomic_dec_if_positive(&hostdata->request_limit); + /* If request limit was -1 when we started, it is now even + * less than that + */ + if (request_status < -1) + goto send_error; + /* Otherwise, if we have run out of requests */ + else if (request_status < 0) + goto send_busy; + } /* Copy the IU into the transfer area */ *evt_struct->xfer_iu = evt_struct->iu; @@ -567,11 +577,23 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, return 0; - send_error: + send_busy: unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; + + send_error: + unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); + + if (evt_struct->cmnd != NULL) { + evt_struct->cmnd->result = DID_ERROR << 16; + evt_struct->cmnd_done(evt_struct->cmnd); + } else if (evt_struct->done) + evt_struct->done(evt_struct); + + free_event_struct(&hostdata->pool, evt_struct); + return 0; } /** @@ -1184,27 +1206,37 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq, return; case 0xFF: /* Hypervisor telling us the connection is closed */ scsi_block_requests(hostdata->host); + atomic_set(&hostdata->request_limit, 0); if (crq->format == 0x06) { /* We need to re-setup the interpartition connection */ printk(KERN_INFO "ibmvscsi: Re-enabling adapter!\n"); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_REQUEUE); - if (ibmvscsi_reenable_crq_queue(&hostdata->queue, - hostdata) == 0) - if (ibmvscsi_send_crq(hostdata, - 0xC001000000000000LL, 0)) + if ((ibmvscsi_reenable_crq_queue(&hostdata->queue, + hostdata) == 0) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); printk(KERN_ERR - "ibmvscsi: transmit error after" + "ibmvscsi: error after" " enable\n"); + } } else { printk(KERN_INFO "ibmvscsi: Virtual adapter failed rc %d!\n", crq->format); - atomic_set(&hostdata->request_limit, -1); purge_requests(hostdata, DID_ERROR); - ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata); + if ((ibmvscsi_reset_crq_queue(&hostdata->queue, + hostdata)) || + (ibmvscsi_send_crq(hostdata, + 0xC001000000000000LL, 0))) { + atomic_set(&hostdata->request_limit, + -1); + printk(KERN_ERR + "ibmvscsi: error after reset\n"); + } } scsi_unblock_requests(hostdata->host); return; @@ -1467,6 +1499,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct Scsi_Host *host; struct device *dev = &vdev->dev; unsigned long wait_switch = 0; + int rc; vdev->dev.driver_data = NULL; @@ -1484,8 +1517,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */ - if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, - max_requests) != 0) { + rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests); + if (rc != 0 && rc != H_RESOURCE) { printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n"); goto init_crq_failed; } @@ -1505,7 +1538,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) * to fail if the other end is not acive. In that case we don't * want to scan */ - if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) { + if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0 + || rc == H_RESOURCE) { /* * Wait around max init_timeout secs for the adapter to finish * initializing. When we are done initializing, we will have a diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c index 1a9992bdfef..242b8873b33 100644 --- a/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c @@ -208,6 +208,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, int max_requests) { int rc; + int retrc; struct vio_dev *vdev = to_vio_dev(hostdata->dev); queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); @@ -226,7 +227,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, gather_partition_info(); set_adapter_info(hostdata); - rc = plpar_hcall_norets(H_REG_CRQ, + retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, queue->msg_token, PAGE_SIZE); if (rc == H_RESOURCE) @@ -263,7 +264,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue, tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task, (unsigned long)hostdata); - return 0; + return retrc; req_irq_failed: do { -- cgit v1.2.3 From 0e98936c924e2329f876b0b7791b45249c2e2129 Mon Sep 17 00:00:00 2001 From: Sumant Patro Date: Tue, 20 Jun 2006 15:32:37 -0700 Subject: [SCSI] megaraid_sas: zcr with fix The patch adds support for a ZCR controller (Device ID : 0x413). It also has a critical bug fix : Disable controller interrupt before firing INIT cmd to FW. Interrupt is enabled after required initialization is over. This is done to ensure that driver is ready to handle interrupts when it is generated by the controller. Signed-off-by: Sumant Patro Signed-off-by: James Bottomley --- Documentation/scsi/ChangeLog.megaraid_sas | 16 ++++++++++++++++ drivers/scsi/megaraid/megaraid_sas.c | 32 +++++++++++++++++++++++-------- drivers/scsi/megaraid/megaraid_sas.h | 21 +++++++++++++++----- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas index 0a85a7e8120..d9e5960dafd 100644 --- a/Documentation/scsi/ChangeLog.megaraid_sas +++ b/Documentation/scsi/ChangeLog.megaraid_sas @@ -1,4 +1,20 @@ +1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro +2 Current Version : 00.00.03.01 +3 Older Version : 00.00.02.04 + +i. Added support for ZCR controller. + + New device id 0x413 added. + +ii. Bug fix : Disable controller interrupt before firing INIT cmd to FW. + + Interrupt is enabled after required initialization is over. + This is done to ensure that driver is ready to handle interrupts when + it is generated by the controller. + + -Sumant Patro + 1 Release Date : Wed Feb 03 14:31:44 PST 2006 - Sumant Patro 2 Current Version : 00.00.02.04 3 Older Version : 00.00.02.04 diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 0c9516ff636..3e6f9feaf69 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.02.04 + * Version : v00.00.03.01 * * Authors: * Sreenivas Bagalkote @@ -55,19 +55,25 @@ static struct pci_device_id megasas_pci_table[] = { { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP + PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LSI_SAS1078R, // ppc IOP + PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */ PCI_ANY_ID, PCI_ANY_ID, }, + { + PCI_VENDOR_ID_LSI_LOGIC, + PCI_DEVICE_ID_LSI_VERDE_ZCR, /* xscale IOP, vega */ + PCI_ANY_ID, + PCI_ANY_ID, + }, { PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_DELL_PERC5, // xscale IOP + PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */ PCI_ANY_ID, PCI_ANY_ID, }, @@ -289,9 +295,14 @@ static struct megasas_instance_template megasas_instance_template_ppc = { * @regs: MFI register set */ static inline void -megasas_disable_intr(struct megasas_register_set __iomem * regs) +megasas_disable_intr(struct megasas_instance *instance) { u32 mask = 0x1f; + struct megasas_register_set __iomem *regs = instance->reg_set; + + if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R) + mask = 0xffffffff; + writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -1260,7 +1271,7 @@ megasas_transition_to_ready(struct megasas_instance* instance) /* * Bring it to READY state; assuming max wait 2 secs */ - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell); max_wait = 10; @@ -1756,6 +1767,11 @@ static int megasas_init_mfi(struct megasas_instance *instance) init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); + /* + * disable the intr before firing the init frame to FW + */ + megasas_disable_intr(instance); + /* * Issue the init frame in polled mode */ @@ -2234,7 +2250,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) megasas_mgmt_info.max_index--; pci_set_drvdata(pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); megasas_release_mfi(instance); @@ -2364,7 +2380,7 @@ static void megasas_detach_one(struct pci_dev *pdev) pci_set_drvdata(instance->pdev, NULL); - megasas_disable_intr(instance->reg_set); + megasas_disable_intr(instance); free_irq(instance->pdev->irq, instance); diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 927d6ffef05..3531a14222a 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,16 @@ /** * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.02.04" -#define MEGASAS_RELDATE "Feb 03, 2006" -#define MEGASAS_EXT_VERSION "Fri Feb 03 14:31:44 PST 2006" +#define MEGASAS_VERSION "00.00.03.01" +#define MEGASAS_RELDATE "May 14, 2006" +#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006" + +/* + * Device IDs + */ +#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060 +#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413 + /* * ===================================== * MegaRAID SAS MFI firmware definitions @@ -554,7 +561,11 @@ struct megasas_ctrl_info { #define MFI_POLL_TIMEOUT_SECS 10 #define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 -#define PCI_DEVICE_ID_LSI_SAS1078R 0x00000060 + +/* +* register set for both 1068 and 1078 controllers +* structure extended for 1078 registers +*/ struct megasas_register_set { u32 reserved_0[4]; /*0000h*/ @@ -1150,10 +1161,10 @@ struct compat_megasas_iocpacket { struct compat_iovec sgl[MAX_IOCTL_SGE]; } __attribute__ ((packed)); +#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #endif #define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) -#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) #define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) struct megasas_mgmt_info { -- cgit v1.2.3 From 9ba0883cfc5ab69820c05f1bf2b7711bb0a0103c Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 22 Jun 2006 09:19:51 +0200 Subject: [SCSI] HP XP devinfo update According to Anthony Cheung all HP XP arrays with "OPEN-" types support REPORT_LUN. So there is no reason why we shouldn't use it. Signed-off-by: Anthony Cheung Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index fb5cb4c9ac6..3d0429bc14a 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -162,7 +162,7 @@ static struct { {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */ + {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, -- cgit v1.2.3 From f89d0a4e1d01168f20f9e8273de7dfc094b2a430 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 22 Jun 2006 11:45:00 +0200 Subject: [SCSI] aic79xx: remove slave_destroy Even with the latest fixes aic79xx still occasionally triggers the BUG_ON in slave_destroy. Rather than trying to figure out the various levels of interaction here I've decided to remove the callback altogether. The primary reason for the slave_alloc / slave_destroy is to keep an index of pointers to the sdevs associated with a given target. However, by changing the arguments to the affected functions slightly it's possible to avoid the use of that index entirely. The only performance penalty we'll incur is in writing the information for /proc/scsi/XXX, as we'll have to recurse over all available sdevs to find the correct ones. But I doubt that reading from /proc is in any way time-critical. Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx.h | 1 + drivers/scsi/aic7xxx/aic79xx_core.c | 24 +++++++------- drivers/scsi/aic7xxx/aic79xx_osm.c | 62 +++++++------------------------------ drivers/scsi/aic7xxx/aic79xx_osm.h | 11 ++----- drivers/scsi/aic7xxx/aic79xx_proc.c | 19 +++++------- 5 files changed, 36 insertions(+), 81 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index eb774569268..df3346b5caf 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1487,6 +1487,7 @@ typedef enum { } ahd_queue_alg; void ahd_set_tags(struct ahd_softc *ahd, + struct scsi_cmnd *cmd, struct ahd_devinfo *devinfo, ahd_queue_alg alg); diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 801fc81d0b2..a1e8ca75859 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -1090,7 +1090,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) /* Notify XPT */ ahd_send_async(ahd, devinfo.channel, devinfo.target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); /* * Allow the sequencer to continue with @@ -3062,7 +3062,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.ppr_options = ppr_options; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { if (offset != 0) { int options; @@ -3184,7 +3184,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, tinfo->curr.width = width; ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL); + CAM_LUN_WILDCARD, AC_TRANSFER_NEG); if (bootverbose) { printf("%s: target %d using %dbit transfers\n", ahd_name(ahd), devinfo->target, @@ -3211,12 +3211,14 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, * Update the current state of tagged queuing for a given target. */ void -ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - ahd_platform_set_tags(ahd, devinfo, alg); + struct scsi_device *sdev = cmd->device; + + ahd_platform_set_tags(ahd, sdev, devinfo, alg); ahd_send_async(ahd, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG, &alg); + devinfo->lun, AC_TRANSFER_NEG); } static void @@ -4746,7 +4748,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) printf("(%s:%c:%d:%d): refuses tagged commands. " "Performing non-tagged I/O\n", ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); mask = ~0x23; } else { printf("(%s:%c:%d:%d): refuses %s tagged commands. " @@ -4754,7 +4756,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) ahd_name(ahd), devinfo->channel, devinfo->target, devinfo->lun, tag_type == MSG_ORDERED_TASK ? "ordered" : "head of queue"); - ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC); + ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC); mask = ~0x03; } @@ -5098,7 +5100,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, if (status != CAM_SEL_TIMEOUT) ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + CAM_LUN_WILDCARD, AC_SENT_BDR); if (message != NULL && bootverbose) printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), @@ -7952,7 +7954,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) #endif /* Notify the XPT that a bus reset occurred */ ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET, NULL); + CAM_LUN_WILDCARD, AC_BUS_RESET); /* * Revert to async/narrow transfers until we renegotiate. diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index e0ccdf36220..b244c712417 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -484,7 +484,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) struct seeprom_config *sc = ahd->seep_config; unsigned long flags; struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_devinfo devinfo; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -495,7 +494,6 @@ ahd_linux_target_alloc(struct scsi_target *starget) BUG_ON(*ahd_targp != NULL); *ahd_targp = starget; - memset(targ, 0, sizeof(*targ)); if (sc) { int flags = sc->device_flags[starget->id]; @@ -551,15 +549,11 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) { struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); - struct scsi_target *starget = sdev->sdev_target; - struct ahd_linux_target *targ = scsi_transport_target_data(starget); struct ahd_linux_device *dev; if (bootverbose) printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); - BUG_ON(targ->sdev[sdev->lun] != NULL); - dev = scsi_transport_device_data(sdev); memset(dev, 0, sizeof(*dev)); @@ -576,8 +570,6 @@ ahd_linux_slave_alloc(struct scsi_device *sdev) */ dev->maxtags = 0; - targ->sdev[sdev->lun] = sdev; - return (0); } @@ -599,23 +591,6 @@ ahd_linux_slave_configure(struct scsi_device *sdev) return 0; } -static void -ahd_linux_slave_destroy(struct scsi_device *sdev) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); - - ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (bootverbose) - printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); - - BUG_ON(dev->active); - - targ->sdev[sdev->lun] = NULL; - -} - #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. @@ -822,7 +797,6 @@ struct scsi_host_template aic79xx_driver_template = { .use_clustering = ENABLE_CLUSTERING, .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, - .slave_destroy = ahd_linux_slave_destroy, .target_alloc = ahd_linux_target_alloc, .target_destroy = ahd_linux_target_destroy, }; @@ -1249,20 +1223,13 @@ void ahd_platform_free(struct ahd_softc *ahd) { struct scsi_target *starget; - int i, j; + int i; if (ahd->platform_data != NULL) { /* destroy all of the device and target objects */ for (i = 0; i < AHD_NUM_TARGETS; i++) { starget = ahd->platform_data->starget[i]; if (starget != NULL) { - for (j = 0; j < AHD_NUM_LUNS; j++) { - struct ahd_linux_target *targ = - scsi_transport_target_data(starget); - if (targ->sdev[j] == NULL) - continue; - targ->sdev[j] = NULL; - } ahd->platform_data->starget[i] = NULL; } } @@ -1318,20 +1285,13 @@ ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) } void -ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, + struct ahd_devinfo *devinfo, ahd_queue_alg alg) { - struct scsi_target *starget; - struct ahd_linux_target *targ; struct ahd_linux_device *dev; - struct scsi_device *sdev; int was_queuing; int now_queuing; - starget = ahd->platform_data->starget[devinfo->target]; - targ = scsi_transport_target_data(starget); - BUG_ON(targ == NULL); - sdev = targ->sdev[devinfo->lun]; if (sdev == NULL) return; @@ -1467,11 +1427,15 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev) tags = ahd_linux_user_tagdepth(ahd, &devinfo); if (tags != 0 && sdev->tagged_supported != 0) { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); ahd_print_devinfo(ahd, &devinfo); printf("Tagged Queuing enabled. Depth %d\n", tags); } else { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); + ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE); + ahd_send_async(ahd, devinfo.channel, devinfo.target, + devinfo.lun, AC_TRANSFER_NEG); } } @@ -1629,7 +1593,7 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) void ahd_send_async(struct ahd_softc *ahd, char channel, - u_int target, u_int lun, ac_code code, void *arg) + u_int target, u_int lun, ac_code code) { switch (code) { case AC_TRANSFER_NEG: @@ -1956,7 +1920,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, } ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; @@ -1966,7 +1930,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, * as if the target returned BUSY SCSI status. */ dev->openings = 1; - ahd_platform_set_tags(ahd, &devinfo, + ahd_platform_set_tags(ahd, sdev, &devinfo, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); @@ -2778,8 +2742,6 @@ ahd_linux_init(void) if (!ahd_linux_transport_template) return -ENODEV; - scsi_transport_reserve_target(ahd_linux_transport_template, - sizeof(struct ahd_linux_target)); scsi_transport_reserve_device(ahd_linux_transport_template, sizeof(struct ahd_linux_device)); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 2b8331649ee..b2e65e10ad2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -263,7 +263,6 @@ typedef enum { AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ } ahd_linux_dev_flags; -struct ahd_linux_target; struct ahd_linux_device { TAILQ_ENTRY(ahd_linux_device) links; @@ -343,12 +342,6 @@ struct ahd_linux_device { #define AHD_OTAG_THRESH 500 }; -struct ahd_linux_target { - struct scsi_device *sdev[AHD_NUM_LUNS]; - struct ahd_transinfo last_tinfo; - struct ahd_softc *ahd; -}; - /********************* Definitions Required by the Core ***********************/ /* * Number of SG segments we require. So long as the S/G segments for @@ -865,7 +858,7 @@ ahd_freeze_scb(struct scb *scb) } } -void ahd_platform_set_tags(struct ahd_softc *ahd, +void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, struct ahd_devinfo *devinfo, ahd_queue_alg); int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, @@ -874,7 +867,7 @@ irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahd_done(struct ahd_softc*, struct scb*); void ahd_send_async(struct ahd_softc *, char channel, - u_int target, u_int lun, ac_code, void *); + u_int target, u_int lun, ac_code); void ahd_print_path(struct ahd_softc *, struct scb *); #ifdef CONFIG_PCI diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 24fd59a230b..c5f0ee59150 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -47,7 +47,7 @@ static int copy_info(struct info_str *info, char *fmt, ...); static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, u_int our_id, char channel, - u_int target_id, u_int target_offset); + u_int target_id); static void ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, @@ -204,10 +204,8 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) static void ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, - u_int our_id, char channel, u_int target_id, - u_int target_offset) + u_int our_id, char channel, u_int target_id) { - struct ahd_linux_target *targ; struct scsi_target *starget; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; @@ -218,10 +216,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "Target %d Negotiation Settings\n", target_id); copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); - starget = ahd->platform_data->starget[target_offset]; + starget = ahd->platform_data->starget[target_id]; if (starget == NULL) return; - targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahd_format_transinfo(info, &tinfo->goal); @@ -231,7 +228,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, for (lun = 0; lun < AHD_NUM_LUNS; lun++) { struct scsi_device *dev; - dev = targ->sdev[lun]; + dev = scsi_device_lookup_by_target(starget, lun); if (dev == NULL) continue; @@ -355,7 +352,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", ahd->scb_data.numscbs, AHD_NSEG); - max_targ = 15; + max_targ = 16; if (ahd->seep_config == NULL) copy_info(&info, "No Serial EEPROM\n"); @@ -373,12 +370,12 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, copy_info(&info, "\n"); if ((ahd->features & AHD_WIDE) == 0) - max_targ = 7; + max_targ = 8; - for (i = 0; i <= max_targ; i++) { + for (i = 0; i < max_targ; i++) { ahd_dump_target_state(ahd, &info, ahd->our_id, 'A', - /*target_id*/i, /*target_offset*/i); + /*target_id*/i); } retval = info.pos > info.offset ? info.pos - info.offset : 0; done: -- cgit v1.2.3 From 03aba2f79594ca94d159c8bab454de9bcc385b76 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Fri, 23 Jun 2006 09:39:09 -0700 Subject: [SCSI] sd/scsi_lib simplify sd_rw_intr and scsi_io_completion This patch simplifies "good_bytes" computation in sd_rw_intr(). sd: "good_bytes" computation is always done in terms of the resolution of the device's medium, since after that it is the number of good bytes we pass around and other layers/contexts (as opposed ot sd) can translate that to their own resolution (block layer:512). It also makes scsi_io_completion() processing more straightforward, eliminating the 3rd argument to the function. It also fixes a couple of bugs like not checking return value, using "break" instead of "return;", etc. I've been running with this patch for some time now on a test (do-it-all) system. Signed-off-by: Luben Tuikov Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 108 ++++++++++++++--------------------- drivers/scsi/sd.c | 143 ++++++++++++++++++++--------------------------- drivers/scsi/sr.c | 2 +- include/scsi/scsi_cmnd.h | 2 +- 4 files changed, 106 insertions(+), 149 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3d04a9f386a..4c4add53d69 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -855,8 +855,7 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd) * b) We can just use scsi_requeue_command() here. This would * be used if we just wanted to retry, for example. */ -void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, - unsigned int block_bytes) +void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) { int result = cmd->result; int this_count = cmd->bufflen; @@ -921,87 +920,72 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, * Next deal with any sectors which we were able to correctly * handle. */ - if (good_bytes >= 0) { - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n", + if (good_bytes > 0) { + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + "%d bytes done.\n", req->nr_sectors, good_bytes)); SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); if (clear_errors) req->errors = 0; - /* - * If multiple sectors are requested in one buffer, then - * they will have been finished off by the first command. - * If not, then we have a multi-buffer command. - * - * If block_bytes != 0, it means we had a medium error - * of some sort, and that we want to mark some number of - * sectors as not uptodate. Thus we want to inhibit - * requeueing right here - we will requeue down below - * when we handle the bad sectors. - */ - /* - * If the command completed without error, then either - * finish off the rest of the command, or start a new one. + /* A number of bytes were successfully read. If there + * is leftovers and there is some kind of error + * (result != 0), retry the rest. */ - if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) + if (scsi_end_request(cmd, 1, good_bytes, !!result) == NULL) return; } - /* - * Now, if we were good little boys and girls, Santa left us a request - * sense buffer. We can extract information from this, so we - * can choose a block to remap, etc. + + /* good_bytes = 0, or (inclusive) there were leftovers and + * result = 0, so scsi_end_request couldn't retry. */ if (sense_valid && !sense_deferred) { switch (sshdr.sense_key) { case UNIT_ATTENTION: if (cmd->device->removable) { - /* detected disc change. set a bit + /* Detected disc change. Set a bit * and quietly refuse further access. */ cmd->device->changed = 1; - scsi_end_request(cmd, 0, - this_count, 1); + scsi_end_request(cmd, 0, this_count, 1); return; } else { - /* - * Must have been a power glitch, or a - * bus reset. Could not have been a - * media change, so we just retry the - * request and see what happens. - */ + /* Must have been a power glitch, or a + * bus reset. Could not have been a + * media change, so we just retry the + * request and see what happens. + */ scsi_requeue_command(q, cmd); return; } break; case ILLEGAL_REQUEST: - /* - * If we had an ILLEGAL REQUEST returned, then we may - * have performed an unsupported command. The only - * thing this should be would be a ten byte read where - * only a six byte read was supported. Also, on a - * system where READ CAPACITY failed, we may have read - * past the end of the disk. - */ + /* If we had an ILLEGAL REQUEST returned, then + * we may have performed an unsupported + * command. The only thing this should be + * would be a ten byte read where only a six + * byte read was supported. Also, on a system + * where READ CAPACITY failed, we may have + * read past the end of the disk. + */ if ((cmd->device->use_10_for_rw && sshdr.asc == 0x20 && sshdr.ascq == 0x00) && (cmd->cmnd[0] == READ_10 || cmd->cmnd[0] == WRITE_10)) { cmd->device->use_10_for_rw = 0; - /* - * This will cause a retry with a 6-byte - * command. + /* This will cause a retry with a + * 6-byte command. */ scsi_requeue_command(q, cmd); - result = 0; + return; } else { scsi_end_request(cmd, 0, this_count, 1); return; } break; case NOT_READY: - /* - * If the device is in the process of becoming + /* If the device is in the process of becoming * ready, or has a temporary blockage, retry. */ if (sshdr.asc == 0x04) { @@ -1021,7 +1005,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, } if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Device not ready: "); + "Device not ready: "); scsi_print_sense_hdr("", &sshdr); } scsi_end_request(cmd, 0, this_count, 1); @@ -1029,21 +1013,21 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, case VOLUME_OVERFLOW: if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "Volume overflow, CDB: "); + "Volume overflow, CDB: "); __scsi_print_command(cmd->data_cmnd); scsi_print_sense("", cmd); } - scsi_end_request(cmd, 0, block_bytes, 1); + /* See SSC3rXX or current. */ + scsi_end_request(cmd, 0, this_count, 1); return; default: break; } - } /* driver byte != 0 */ + } if (host_byte(result) == DID_RESET) { - /* - * Third party bus reset or reset for error - * recovery reasons. Just retry the request - * and see what happens. + /* Third party bus reset or reset for error recovery + * reasons. Just retry the request and see what + * happens. */ scsi_requeue_command(q, cmd); return; @@ -1051,21 +1035,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, if (result) { if (!(req->flags & REQ_QUIET)) { scmd_printk(KERN_INFO, cmd, - "SCSI error: return code = 0x%x\n", result); - + "SCSI error: return code = 0x%08x\n", + result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); } - /* - * Mark a single buffer as not uptodate. Queue the remainder. - * We sometimes get this cruft in the event that a medium error - * isn't properly reported. - */ - block_bytes = req->hard_cur_sectors << 9; - if (!block_bytes) - block_bytes = req->data_len; - scsi_end_request(cmd, 0, block_bytes, 1); } + scsi_end_request(cmd, 0, this_count, !result); } EXPORT_SYMBOL(scsi_io_completion); @@ -1169,7 +1145,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd) * successfully. Since this is a REQ_BLOCK_PC command the * caller should check the request's errors value */ - scsi_io_completion(cmd, cmd->bufflen, 0); + scsi_io_completion(cmd, cmd->bufflen); } static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 35419901124..f899ff0cf00 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -891,11 +891,10 @@ static struct block_device_operations sd_fops = { static void sd_rw_intr(struct scsi_cmnd * SCpnt) { int result = SCpnt->result; - int this_count = SCpnt->request_bufflen; - int good_bytes = (result == 0 ? this_count : 0); - sector_t block_sectors = 1; - u64 first_err_block; - sector_t error_sector; + unsigned int xfer_size = SCpnt->request_bufflen; + unsigned int good_bytes = result ? 0 : xfer_size; + u64 start_lba = SCpnt->request->sector; + u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; @@ -906,7 +905,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); } - #ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); @@ -916,89 +914,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) sshdr.sense_key, sshdr.asc, sshdr.ascq)); } #endif - /* - Handle MEDIUM ERRORs that indicate partial success. Since this is a - relatively rare error condition, no care is taken to avoid - unnecessary additional work such as memcpy's that could be avoided. - */ - if (driver_byte(result) != 0 && - sense_valid && !sense_deferred) { - switch (sshdr.sense_key) { - case MEDIUM_ERROR: - if (!blk_fs_request(SCpnt->request)) - break; - info_valid = scsi_get_sense_info_fld( - SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &first_err_block); - /* - * May want to warn and skip if following cast results - * in actual truncation (if sector_t < 64 bits) - */ - error_sector = (sector_t)first_err_block; - if (SCpnt->request->bio != NULL) - block_sectors = bio_sectors(SCpnt->request->bio); - switch (SCpnt->device->sector_size) { - case 1024: - error_sector <<= 1; - if (block_sectors < 2) - block_sectors = 2; - break; - case 2048: - error_sector <<= 2; - if (block_sectors < 4) - block_sectors = 4; - break; - case 4096: - error_sector <<=3; - if (block_sectors < 8) - block_sectors = 8; - break; - case 256: - error_sector >>= 1; - break; - default: - break; - } + if (driver_byte(result) != DRIVER_SENSE && + (!sense_valid || sense_deferred)) + goto out; - error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - SCpnt->request->sector) << 9; - if (good_bytes < 0 || good_bytes >= this_count) - good_bytes = 0; + switch (sshdr.sense_key) { + case HARDWARE_ERROR: + case MEDIUM_ERROR: + if (!blk_fs_request(SCpnt->request)) + goto out; + info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + &bad_lba); + if (!info_valid) + goto out; + if (xfer_size <= SCpnt->device->sector_size) + goto out; + switch (SCpnt->device->sector_size) { + case 256: + start_lba <<= 1; break; - - case RECOVERED_ERROR: /* an error occurred, but it recovered */ - case NO_SENSE: /* LLDD got sense data */ - /* - * Inform the user, but make sure that it's not treated - * as a hard error. - */ - scsi_print_sense("sd", SCpnt); - SCpnt->result = 0; - memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - good_bytes = this_count; + case 512: break; - - case ILLEGAL_REQUEST: - if (SCpnt->device->use_10_for_rw && - (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10)) - SCpnt->device->use_10_for_rw = 0; - if (SCpnt->device->use_10_for_ms && - (SCpnt->cmnd[0] == MODE_SENSE_10 || - SCpnt->cmnd[0] == MODE_SELECT_10)) - SCpnt->device->use_10_for_ms = 0; + case 1024: + start_lba >>= 1; + break; + case 2048: + start_lba >>= 2; + break; + case 4096: + start_lba >>= 3; break; - default: + /* Print something here with limiting frequency. */ + goto out; break; } + /* This computation should always be done in terms of + * the resolution of the device's medium. + */ + good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size; + break; + case RECOVERED_ERROR: + case NO_SENSE: + /* Inform the user, but make sure that it's not treated + * as a hard error. + */ + scsi_print_sense("sd", SCpnt); + SCpnt->result = 0; + memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); + good_bytes = xfer_size; + break; + case ILLEGAL_REQUEST: + if (SCpnt->device->use_10_for_rw && + (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10)) + SCpnt->device->use_10_for_rw = 0; + if (SCpnt->device->use_10_for_ms && + (SCpnt->cmnd[0] == MODE_SENSE_10 || + SCpnt->cmnd[0] == MODE_SELECT_10)) + SCpnt->device->use_10_for_ms = 0; + break; + default: + break; } - /* - * This calls the generic completion function, now that we know - * how many actual sectors finished, and how many sectors we need - * to say have failed. - */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + out: + scsi_io_completion(SCpnt, good_bytes); } static int media_not_present(struct scsi_disk *sdkp, diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index ebf6579ed69..fd94408577e 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt) * how many actual sectors finished, and how many sectors we need * to say have failed. */ - scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); + scsi_io_completion(SCpnt, good_bytes); } static int sr_init_command(struct scsi_cmnd * SCpnt) diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index e46cd404bd7..371f70d9aa9 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -143,7 +143,7 @@ struct scsi_cmnd { extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); extern void scsi_put_command(struct scsi_cmnd *); -extern void scsi_io_completion(struct scsi_cmnd *, unsigned int, unsigned int); +extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_finish_command(struct scsi_cmnd *cmd); extern void scsi_req_abort_cmd(struct scsi_cmnd *cmd); -- cgit v1.2.3 From 9ea7290902abcf22f796e9aeae4dc2e71d3f7e67 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 23 Jun 2006 14:25:34 -0400 Subject: [SCSI] SCSI core: Allow QUIESCE -> CANCEL sdev transition We have to be able to remove SCSI devices even when they are suspended, so QUIESCE -> CANCEL must be a legal state transition. This patch (as727) adds the transition to the state machine. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 4c4add53d69..68e0d7dbe6c 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2026,6 +2026,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) switch (oldstate) { case SDEV_CREATED: case SDEV_RUNNING: + case SDEV_QUIESCE: case SDEV_OFFLINE: case SDEV_BLOCK: break; -- cgit v1.2.3 From a7a167bf7e2d196fc33f292e7b02e90fee03bc9a Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:29 -0700 Subject: [SCSI] qla2xxx: Rework firmware-trace facilities. - Defer firmware dump-data raw-to-textual conversion to user-space. - Add module parameter (ql2xallocfwdump) to allow for per-HBA allocations of firmware dump memory. - Dump request and response queue data as per firmware group request. - Add extended firmware trace support for ISP24XX/ISP54XX chips. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 53 +-- drivers/scsi/qla2xxx/qla_dbg.c | 925 ++++++++-------------------------------- drivers/scsi/qla2xxx/qla_dbg.h | 41 +- drivers/scsi/qla2xxx/qla_def.h | 12 +- drivers/scsi/qla2xxx/qla_gbl.h | 9 +- drivers/scsi/qla2xxx/qla_init.c | 104 ++++- drivers/scsi/qla2xxx/qla_mbx.c | 42 ++ drivers/scsi/qla2xxx/qla_os.c | 26 +- 8 files changed, 401 insertions(+), 811 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index e96d58ded57..78eec679934 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off, { struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); + char *rbuf = (char *)ha->fw_dump; if (ha->fw_dump_reading == 0) return 0; - if (off > ha->fw_dump_buffer_len) - return 0; - if (off + count > ha->fw_dump_buffer_len) - count = ha->fw_dump_buffer_len - off; + if (off > ha->fw_dump_len) + return 0; + if (off + count > ha->fw_dump_len) + count = ha->fw_dump_len - off; - memcpy(buf, &ha->fw_dump_buffer[off], count); + memcpy(buf, &rbuf[off], count); return (count); } @@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, struct device, kobj))); int reading; - uint32_t dump_size; if (off != 0) return (0); @@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off, reading = simple_strtol(buf, NULL, 10); switch (reading) { case 0: - if (ha->fw_dump_reading == 1) { - qla_printk(KERN_INFO, ha, - "Firmware dump cleared on (%ld).\n", ha->host_no); + if (!ha->fw_dump_reading) + break; - vfree(ha->fw_dump_buffer); - ha->fw_dump_buffer = NULL; - ha->fw_dump_reading = 0; - ha->fw_dumped = 0; - } + qla_printk(KERN_INFO, ha, + "Firmware dump cleared on (%ld).\n", ha->host_no); + + ha->fw_dump_reading = 0; + ha->fw_dumped = 0; break; case 1: if (ha->fw_dumped && !ha->fw_dump_reading) { ha->fw_dump_reading = 1; - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) - dump_size = FW_DUMP_SIZE_24XX; - else { - dump_size = FW_DUMP_SIZE_1M; - if (ha->fw_memory_size < 0x20000) - dump_size = FW_DUMP_SIZE_128K; - else if (ha->fw_memory_size < 0x80000) - dump_size = FW_DUMP_SIZE_512K; - } - ha->fw_dump_buffer = (char *)vmalloc(dump_size); - if (ha->fw_dump_buffer == NULL) { - qla_printk(KERN_WARNING, ha, - "Unable to allocate memory for firmware " - "dump buffer (%d).\n", dump_size); - - ha->fw_dump_reading = 0; - return (count); - } qla_printk(KERN_INFO, ha, - "Firmware dump ready for read on (%ld).\n", + "Raw firmware dump ready for read on (%ld).\n", ha->host_no); - memset(ha->fw_dump_buffer, 0, dump_size); - ha->isp_ops.ascii_fw_dump(ha); - ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer); } break; + case 2: + qla2x00_alloc_fw_dump(ha); + break; } return (count); } diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 74e54713aa7..f6ed6962bc2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -8,7 +8,34 @@ #include -static int qla_uprintf(char **, char *, ...); +static inline void +qla2xxx_prep_dump(scsi_qla_host_t *ha, struct qla2xxx_fw_dump *fw_dump) +{ + fw_dump->fw_major_version = htonl(ha->fw_major_version); + fw_dump->fw_minor_version = htonl(ha->fw_minor_version); + fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version); + fw_dump->fw_attributes = htonl(ha->fw_attributes); + + fw_dump->vendor = htonl(ha->pdev->vendor); + fw_dump->device = htonl(ha->pdev->device); + fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor); + fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device); +} + +static inline void * +qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr) +{ + /* Request queue. */ + memcpy(ptr, ha->request_ring, ha->request_q_length * + sizeof(request_t)); + + /* Response queue. */ + ptr += ha->request_q_length * sizeof(request_t); + memcpy(ptr, ha->response_ring, ha->response_q_length * + sizeof(response_t)); + + return ptr + (ha->response_q_length * sizeof(response_t)); +} /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. @@ -49,10 +76,11 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2300_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp23; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -73,85 +101,86 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) - fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x40); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) - fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x50); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2800); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2A00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2C00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2E00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -226,7 +255,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -285,7 +314,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->stack_ram[cnt] = mb2; + fw->stack_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } @@ -345,12 +374,15 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->data_ram[cnt] = mb2; + fw->data_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->data_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -368,193 +400,6 @@ qla2300_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -/** - * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2300_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2300_fw_dump *fw; - uint32_t data_ram_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nStack RAM Dump:"); - for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000); - } - qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nData RAM Dump:"); - data_ram_cnt = ha->fw_memory_size - 0x11000 + 1; - for (cnt = 0; cnt < data_ram_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000); - } - qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); -} - /** * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. * @ha: HA context @@ -591,10 +436,11 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla2100_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp21; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->hccr = RD_REG_WORD(®->hccr); + fw->hccr = htons(RD_REG_WORD(®->hccr)); /* Pause RISC. */ WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); @@ -608,79 +454,81 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (rval == QLA_SUCCESS) { dmp_reg = (uint16_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10); for (cnt = 0; cnt < ha->mbx_count; cnt++) { if (cnt == 8) { - dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0); + dmp_reg = (uint16_t __iomem *) + ((uint8_t __iomem *)reg + 0xe0); } - fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); } dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20); for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x00); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0); for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2000); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) - fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2100); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) - fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2200); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) - fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2300); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) - fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2400); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) - fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2500); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) - fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2600); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) - fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->pcr, 0x2700); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) - fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x10); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) - fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->frame_buf_hdw_reg[cnt] = + htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x20); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) - fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); WRT_REG_WORD(®->ctrl_status, 0x30); dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) - fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++); + fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); /* Reset the ISP. */ WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); @@ -755,12 +603,15 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = mb2; + fw->risc_ram[cnt] = htons(mb2); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) + qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -778,179 +629,6 @@ qla2100_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -/** - * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII. - * @ha: HA context - */ -void -qla2100_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - char fw_info[30]; - struct qla2100_fw_dump *fw; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number, - ha->isp_ops.fw_version_str(ha, fw_info)); - - qla_uprintf(&uiter, "\n[==>BEG]\n"); - - qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr); - - qla_uprintf(&uiter, "PBIU Registers:"); - for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers:"); - for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nDMA Registers:"); - for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP2 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP3 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP4 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP5 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP6 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP7 Registers:"); - for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:"); - for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B0 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM B1 Registers:"); - for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n"); - } - qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC SRAM:"); - for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000); - } - qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump."); - - return; -} - -static int -qla_uprintf(char **uiter, char *fmt, ...) -{ - int iter, len; - char buf[128]; - va_list args; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - for (iter = 0; iter < len; iter++, *uiter += 1) - *uiter[0] = buf[iter]; - - return (len); -} - - void qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) { @@ -967,6 +645,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) unsigned long flags; struct qla24xx_fw_dump *fw; uint32_t ext_mem_cnt; + void *eft; risc_address = ext_mem_cnt = 0; memset(mb, 0, sizeof(mb)); @@ -987,10 +666,11 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) "request...\n", ha->fw_dump); goto qla24xx_fw_dump_failed; } - fw = ha->fw_dump; + fw = &ha->fw_dump->isp.isp24; + qla2xxx_prep_dump(ha, ha->fw_dump); rval = QLA_SUCCESS; - fw->host_status = RD_REG_DWORD(®->host_status); + fw->host_status = htonl(RD_REG_DWORD(®->host_status)); /* Pause RISC. */ if ((RD_REG_DWORD(®->hccr) & HCCRX_RISC_PAUSE) == 0) { @@ -1012,7 +692,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) /* Host interface registers. */ dmp_reg = (uint32_t __iomem *)(reg + 0); for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Disable interrupts. */ WRT_REG_DWORD(®->ictrl, 0); @@ -1024,470 +704,471 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0000000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0100000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0200000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0300000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0400000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0500000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0); WRT_REG_DWORD(dmp_reg, 0xB0600000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC); - fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg)); /* Mailbox registers. */ mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80); for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = RD_REG_WORD(mbx_reg++); + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); /* Transfer sequence registers. */ iter_reg = fw->xseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xBF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) - fw->xseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xBFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) - fw->xseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Receive sequence registers. */ iter_reg = fw->rseq_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0xFF00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFF70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFD0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) - fw->rseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFE0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) - fw->rseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0xFFF0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) - fw->rseq_2_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Command DMA registers. */ WRT_REG_DWORD(®->iobase_addr, 0x7100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) - fw->cmd_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); /* Queues. */ iter_reg = fw->req0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7200); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->resp0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7300); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->req1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7400); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4); for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Transmit DMA registers. */ iter_reg = fw->xmt0_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7600); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7610); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt1_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7620); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7630); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt2_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7640); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7650); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt3_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7660); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7670); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->xmt4_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7680); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7690); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x76A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) - fw->xmt_data_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++); + fw->xmt_data_dma_reg[cnt] = + htonl(RD_REG_DWORD(dmp_reg++)); /* Receive DMA registers. */ iter_reg = fw->rcvt0_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7700); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7710); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); iter_reg = fw->rcvt1_data_dma_reg; WRT_REG_DWORD(®->iobase_addr, 0x7720); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x7730); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* RISC registers. */ iter_reg = fw->risc_gp_reg; WRT_REG_DWORD(®->iobase_addr, 0x0F00); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F10); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F20); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F30); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F40); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F50); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F60); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x0F70); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Local memory controller registers. */ iter_reg = fw->lmc_reg; WRT_REG_DWORD(®->iobase_addr, 0x3000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x3060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Fibre Protocol Module registers. */ iter_reg = fw->fpm_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x4000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4050); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4060); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4070); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4080); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x4090); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40A0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x40B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Frame Buffer registers. */ iter_reg = fw->fb_hdw_reg; WRT_REG_DWORD(®->iobase_addr, 0x6000); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6010); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6020); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6030); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6040); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6100); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6130); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6150); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6170); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x6190); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); WRT_REG_DWORD(®->iobase_addr, 0x61B0); dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0); for (cnt = 0; cnt < 16; cnt++) - *iter_reg++ = RD_REG_DWORD(dmp_reg++); + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); /* Reset RISC. */ WRT_REG_DWORD(®->ctrl_status, @@ -1577,7 +1258,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->code_ram[cnt] = (mb[3] << 16) | mb[2]; + fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } @@ -1627,12 +1308,18 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked) if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { rval = mb[0] & MBS_MASK; - fw->ext_mem[cnt] = (mb[3] << 16) | mb[2]; + fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]); } else { rval = QLA_FUNCTION_FAILED; } } + if (rval == QLA_SUCCESS) { + eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]); + if (ha->eft) + memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size)); + } + if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -1650,252 +1337,6 @@ qla24xx_fw_dump_failed: spin_unlock_irqrestore(&ha->hardware_lock, flags); } -void -qla24xx_ascii_fw_dump(scsi_qla_host_t *ha) -{ - uint32_t cnt; - char *uiter; - struct qla24xx_fw_dump *fw; - uint32_t ext_mem_cnt; - - uiter = ha->fw_dump_buffer; - fw = ha->fw_dump; - - qla_uprintf(&uiter, "ISP FW Version %d.%02d.%02d Attributes %04x\n", - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, ha->fw_attributes); - - qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status); - - qla_uprintf(&uiter, "\nHost Interface Registers"); - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nShadow Registers"); - for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nMailbox Registers"); - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->mailbox_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ GP Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-0 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_0_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-1 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_1_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRSEQ-2 Registers"); - for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rseq_2_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCommand DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->cmd_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nResponse0 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->resp0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->resp0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRequest1 Queue DMA Channel Registers"); - for (cnt = 0; cnt < sizeof(fw->req1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->req1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt0_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt0_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt1_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt1_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT2 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt2_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt2_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT3 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt3_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt3_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT4 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt4_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt4_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nXMT Data DMA Common Registers"); - for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->xmt_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 0 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt0_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt0_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRCV Thread 1 Data DMA Registers"); - for (cnt = 0; cnt < sizeof(fw->rcvt1_data_dma_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->rcvt1_data_dma_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nRISC GP Registers"); - for (cnt = 0; cnt < sizeof(fw->risc_gp_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nLMC Registers"); - for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->lmc_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFPM Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fpm_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fpm_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nFB Hardware Registers"); - for (cnt = 0; cnt < sizeof(fw->fb_hdw_reg) / 4; cnt++) { - if (cnt % 8 == 0) - qla_uprintf(&uiter, "\n"); - - qla_uprintf(&uiter, "%08x ", fw->fb_hdw_reg[cnt]); - } - - qla_uprintf(&uiter, "\n\nCode RAM"); - for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x20000); - } - qla_uprintf(&uiter, "%08x ", fw->code_ram[cnt]); - } - - qla_uprintf(&uiter, "\n\nExternal Memory"); - ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1; - for (cnt = 0; cnt < ext_mem_cnt; cnt++) { - if (cnt % 8 == 0) { - qla_uprintf(&uiter, "\n%08x: ", cnt + 0x100000); - } - qla_uprintf(&uiter, "%08x ", fw->ext_mem[cnt]); - } - - qla_uprintf(&uiter, "\n[<==END] ISP Debug Dump"); -} - - /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index ab6afeaa2f2..ace6afdfe70 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -176,9 +176,6 @@ /* * Firmware Dump structure definition */ -#define FW_DUMP_SIZE_128K 0xBC000 -#define FW_DUMP_SIZE_512K 0x2FC000 -#define FW_DUMP_SIZE_1M 0x5FC000 struct qla2300_fw_dump { uint16_t hccr; @@ -224,8 +221,6 @@ struct qla2100_fw_dump { uint16_t risc_ram[0xf000]; }; -#define FW_DUMP_SIZE_24XX 0x2B0000 - struct qla24xx_fw_dump { uint32_t host_status; uint32_t host_reg[32]; @@ -257,3 +252,39 @@ struct qla24xx_fw_dump { uint32_t code_ram[0x2000]; uint32_t ext_mem[1]; }; + +#define EFT_NUM_BUFFERS 4 +#define EFT_BYTES_PER_BUFFER 0x4000 +#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) + +struct qla2xxx_fw_dump { + uint8_t signature[4]; + uint32_t version; + + uint32_t fw_major_version; + uint32_t fw_minor_version; + uint32_t fw_subminor_version; + uint32_t fw_attributes; + + uint32_t vendor; + uint32_t device; + uint32_t subsystem_vendor; + uint32_t subsystem_device; + + uint32_t fixed_size; + uint32_t mem_size; + uint32_t req_q_size; + uint32_t rsp_q_size; + + uint32_t eft_size; + uint32_t eft_addr_l; + uint32_t eft_addr_h; + + uint32_t header_size; + + union { + struct qla2100_fw_dump isp21; + struct qla2300_fw_dump isp23; + struct qla24xx_fw_dump isp24; + } isp; +}; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d6f6579cfd2..653e22e490a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -608,6 +608,7 @@ typedef struct { #define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */ #define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */ #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ +#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ @@ -618,6 +619,9 @@ typedef struct { #define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ #define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ +#define TC_ENABLE 4 +#define TC_DISABLE 5 + /* Firmware return data sizes */ #define FCAL_MAP_SIZE 128 @@ -1997,7 +2001,6 @@ struct isp_operations { uint32_t); void (*fw_dump) (struct scsi_qla_host *, int); - void (*ascii_fw_dump) (struct scsi_qla_host *); int (*beacon_on) (struct scsi_qla_host *); int (*beacon_off) (struct scsi_qla_host *); @@ -2303,11 +2306,12 @@ typedef struct scsi_qla_host { uint16_t fw_seriallink_options24[4]; /* Firmware dump information. */ - void *fw_dump; + struct qla2xxx_fw_dump *fw_dump; + uint32_t fw_dump_len; int fw_dumped; int fw_dump_reading; - char *fw_dump_buffer; - int fw_dump_buffer_len; + dma_addr_t eft_dma; + void *eft; uint8_t host_str[16]; uint32_t pci_attr; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 164d53ccbfd..fec1e1c9381 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -51,6 +51,8 @@ extern int qla2x00_abort_isp(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *); +extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); + /* * Global Data in qla_os.c source file. */ @@ -61,6 +63,7 @@ extern int qlport_down_retry; extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; +extern int ql2xallocfwdump; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -204,6 +207,9 @@ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); extern int qla2x00_stop_firmware(scsi_qla_host_t *); +extern int +qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); + /* * Global Function Prototypes in qla_isr.c source file. */ @@ -254,9 +260,6 @@ extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, extern void qla2100_fw_dump(scsi_qla_host_t *, int); extern void qla2300_fw_dump(scsi_qla_host_t *, int); extern void qla24xx_fw_dump(scsi_qla_host_t *, int); -extern void qla2100_ascii_fw_dump(scsi_qla_host_t *); -extern void qla2300_ascii_fw_dump(scsi_qla_host_t *); -extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index aef093db597..880de6f380e 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -770,29 +770,104 @@ qla24xx_chip_diag(scsi_qla_host_t *ha) return rval; } -static void +void qla2x00_alloc_fw_dump(scsi_qla_host_t *ha) { - uint32_t dump_size = 0; + int rval; + uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, + eft_size; + dma_addr_t eft_dma; + void *eft; + + if (ha->fw_dump) { + qla_printk(KERN_WARNING, ha, + "Firmware dump previously allocated.\n"); + return; + } ha->fw_dumped = 0; + fixed_size = mem_size = eft_size = 0; if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - dump_size = sizeof(struct qla2100_fw_dump); + fixed_size = sizeof(struct qla2100_fw_dump); } else if (IS_QLA23XX(ha)) { - dump_size = sizeof(struct qla2300_fw_dump); - dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t); - } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { - dump_size = sizeof(struct qla24xx_fw_dump); - dump_size += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t); + fixed_size = offsetof(struct qla2300_fw_dump, data_ram); + mem_size = (ha->fw_memory_size - 0x11000 + 1) * + sizeof(uint16_t); + } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); + mem_size = (ha->fw_memory_size - 0x100000 + 1) * + sizeof(uint32_t); + + /* Allocate memory for Extended Trace Buffer. */ + eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma, + GFP_KERNEL); + if (!eft) { + qla_printk(KERN_WARNING, ha, "Unable to allocate " + "(%d KB) for EFT.\n", EFT_SIZE / 1024); + goto cont_alloc; + } + + rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma, + EFT_NUM_BUFFERS); + if (rval) { + qla_printk(KERN_WARNING, ha, "Unable to initialize " + "EFT (%d).\n", rval); + dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft, + eft_dma); + goto cont_alloc; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n", + EFT_SIZE / 1024); + + eft_size = EFT_SIZE; + memset(eft, 0, eft_size); + ha->eft_dma = eft_dma; + ha->eft = eft; } +cont_alloc: + req_q_size = ha->request_q_length * sizeof(request_t); + rsp_q_size = ha->response_q_length * sizeof(response_t); + + dump_size = offsetof(struct qla2xxx_fw_dump, isp); + dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + + eft_size; ha->fw_dump = vmalloc(dump_size); - if (ha->fw_dump) - qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware " - "dump...\n", dump_size / 1024); - else + if (!ha->fw_dump) { qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for " "firmware dump!!!\n", dump_size / 1024); + + if (ha->eft) { + dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft, + ha->eft_dma); + ha->eft = NULL; + ha->eft_dma = 0; + } + return; + } + + qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n", + dump_size / 1024); + + ha->fw_dump_len = dump_size; + ha->fw_dump->signature[0] = 'Q'; + ha->fw_dump->signature[1] = 'L'; + ha->fw_dump->signature[2] = 'G'; + ha->fw_dump->signature[3] = 'C'; + ha->fw_dump->version = __constant_htonl(1); + + ha->fw_dump->fixed_size = htonl(fixed_size); + ha->fw_dump->mem_size = htonl(mem_size); + ha->fw_dump->req_q_size = htonl(req_q_size); + ha->fw_dump->rsp_q_size = htonl(rsp_q_size); + + ha->fw_dump->eft_size = htonl(eft_size); + ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); + ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); + + ha->fw_dump->header_size = + htonl(offsetof(struct qla2xxx_fw_dump, isp)); } /** @@ -810,8 +885,6 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha) dma_addr_t request_dma; request_t *request_ring; - qla2x00_alloc_fw_dump(ha); - /* Valid only on recent ISPs. */ if (IS_QLA2100(ha) || IS_QLA2200(ha)) return; @@ -883,6 +956,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha) &ha->fw_subminor_version, &ha->fw_attributes, &ha->fw_memory_size); qla2x00_resize_request_q(ha); + + if (ql2xallocfwdump) + qla2x00_alloc_fw_dump(ha); } } else { DEBUG2(printk(KERN_INFO diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d6cb3bd1a29..39ddd38e747 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2460,3 +2460,45 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha) return rval; } + +int +qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, + uint16_t buffers) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_TRACE_CONTROL; + mcp->mb[1] = ctrl; + mcp->out_mb = MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + if (ctrl == TC_ENABLE) { + mcp->mb[2] = LSW(eft_dma); + mcp->mb[3] = MSW(eft_dma); + mcp->mb[4] = LSW(MSD(eft_dma)); + mcp->mb[5] = MSW(MSD(eft_dma)); + mcp->mb[6] = buffers; + mcp->mb[7] = buffers; + mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2; + } + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n", + __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} + + diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index ccaad0b08d3..c16154c5129 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -54,6 +54,13 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); +int ql2xallocfwdump = 1; +module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xallocfwdump, + "Option to enable allocation of memory for a firmware dump " + "during HBA initialization. Memory allocation requirements " + "vary by ISP type. Default is 1 - allocate memory."); + static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); @@ -1405,7 +1412,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla2x00_read_nvram_data; ha->isp_ops.write_nvram = qla2x00_write_nvram_data; ha->isp_ops.fw_dump = qla2100_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; ha->isp_ops.read_optrom = qla2x00_read_optrom_data; ha->isp_ops.write_optrom = qla2x00_write_optrom_data; if (IS_QLA2100(ha)) { @@ -1432,7 +1438,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.pci_config = qla2300_pci_config; ha->isp_ops.intr_handler = qla2300_intr_handler; ha->isp_ops.fw_dump = qla2300_fw_dump; - ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump; ha->isp_ops.beacon_on = qla2x00_beacon_on; ha->isp_ops.beacon_off = qla2x00_beacon_off; ha->isp_ops.beacon_blink = qla2x00_beacon_blink; @@ -1469,7 +1474,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev) ha->isp_ops.read_nvram = qla24xx_read_nvram_data; ha->isp_ops.write_nvram = qla24xx_write_nvram_data; ha->isp_ops.fw_dump = qla24xx_fw_dump; - ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump; ha->isp_ops.read_optrom = qla24xx_read_optrom_data; ha->isp_ops.write_optrom = qla24xx_write_optrom_data; ha->isp_ops.beacon_on = qla24xx_beacon_on; @@ -1678,6 +1682,9 @@ qla2x00_free_device(scsi_qla_host_t *ha) kthread_stop(t); } + if (ha->eft) + qla2x00_trace_control(ha, TC_DISABLE, 0, 0); + /* Stop currently executing firmware. */ qla2x00_stop_firmware(ha); @@ -2012,6 +2019,13 @@ qla2x00_mem_free(scsi_qla_host_t *ha) /* free sp pool */ qla2x00_free_sp_pool(ha); + if (ha->fw_dump) { + if (ha->eft) + dma_free_coherent(&ha->pdev->dev, + ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); + vfree(ha->fw_dump); + } + if (ha->sns_cmd) dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); @@ -2043,6 +2057,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha) (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring, ha->request_dma); + ha->eft = NULL; + ha->eft_dma = 0; ha->sns_cmd = NULL; ha->sns_cmd_dma = 0; ha->ct_sns = NULL; @@ -2071,13 +2087,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } INIT_LIST_HEAD(&ha->fcports); - vfree(ha->fw_dump); - vfree(ha->fw_dump_buffer); - ha->fw_dump = NULL; ha->fw_dumped = 0; ha->fw_dump_reading = 0; - ha->fw_dump_buffer = NULL; vfree(ha->optrom_buffer); } -- cgit v1.2.3 From 395e0808fad28b08b982dd9f299fe4723e7c579b Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:34 -0700 Subject: [SCSI] qla2xxx: Resync with latest HBA SSID specification -- 2.2j. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_devtbl.h | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h index a8fc0ffc7fc..dd435410dfa 100644 --- a/drivers/scsi/qla2xxx/qla_devtbl.h +++ b/drivers/scsi/qla2xxx/qla_devtbl.h @@ -1,4 +1,4 @@ -#define QLA_MODEL_NAMES 0x4A +#define QLA_MODEL_NAMES 0x57 /* * Adapter model names and descriptions. @@ -76,6 +76,19 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = { "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ - " ", " ", /* 0x148 */ + "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */ "QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */ + " ", " ", /* 0x14a */ + " ", " ", /* 0x14b */ + "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */ + "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */ + "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */ + " ", " ", /* 0x14f */ + " ", " ", /* 0x150 */ + " ", " ", /* 0x151 */ + "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */ + "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */ + " ", " ", /* 0x154 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */ + "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */ }; -- cgit v1.2.3 From d4c760c2119fca982f335d83ff9095479c5d6737 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:39 -0700 Subject: [SCSI] qla2xxx: Add NVRAM 'Disable Serdes' bit support. The host section of ISP24xx NVRAMs contain a new bit which allows a user to selectively disable ports of an HBA. These ports (hosts) will not be presented to the midlayer. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_fw.h | 2 +- drivers/scsi/qla2xxx/qla_init.c | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 653e22e490a..dfcd3a2dd7c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2044,6 +2044,7 @@ typedef struct scsi_qla_host { uint32_t enable_led_scheme :1; uint32_t msi_enabled :1; uint32_t msix_enabled :1; + uint32_t disable_serdes :1; } flags; atomic_t loop_state; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 3af478663be..af023f51fe7 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -141,7 +141,7 @@ struct nvram_24xx { * BIT 2 = Enable Memory Map BIOS * BIT 3 = Enable Selectable Boot * BIT 4 = Disable RISC code load - * BIT 5 = + * BIT 5 = Disable Serdes * BIT 6 = * BIT 7 = * diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 880de6f380e..2ccdd848bcf 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -89,6 +89,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->isp_ops.nvram_config(ha); + if (ha->flags.disable_serdes) { + /* Mask HBA via NVRAM settings? */ + qla_printk(KERN_INFO, ha, "Masking HBA WWPN " + "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n", + ha->port_name[0], ha->port_name[1], + ha->port_name[2], ha->port_name[3], + ha->port_name[4], ha->port_name[5], + ha->port_name[6], ha->port_name[7]); + return QLA_FUNCTION_FAILED; + } + qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n"); retry = 10; @@ -1639,6 +1650,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; + ha->flags.disable_serdes = 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; @@ -3450,6 +3462,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_full_login = 1; ha->flags.enable_target_reset = 1; ha->flags.enable_led_scheme = 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & (BIT_6 | BIT_5 | BIT_4)) >> 4; -- cgit v1.2.3 From 8baa51a6f027a2f581930da12f867d8054907656 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:44 -0700 Subject: [SCSI] qla2xxx: Honour 'skip process-login' option during fabric-login IOCB. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mbx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 39ddd38e747..3b16d6f2ee9 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1458,6 +1458,8 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI); + if (opt & BIT_1) + lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; -- cgit v1.2.3 From 88729e53a4798df20e7a7ef68e0a816f4a268da4 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:50 -0700 Subject: [SCSI] qla2xxx: Add DMI (Diagnostics Monitoring Interface) support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 53 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_def.h | 6 +++++ drivers/scsi/qla2xxx/qla_gbl.h | 3 +++ drivers/scsi/qla2xxx/qla_mbx.c | 36 ++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_os.c | 23 ++++++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 78eec679934..1a766b284cf 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -338,6 +338,53 @@ static struct bin_attribute sysfs_vpd_attr = { .write = qla2x00_sysfs_write_vpd, }; +static ssize_t +qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, + struct device, kobj))); + uint16_t iter, addr, offset; + int rval; + + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) + return 0; + + addr = 0xa0; + for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; + iter++, offset += SFP_BLOCK_SIZE) { + if (iter == 4) { + /* Skip to next device address. */ + addr = 0xa2; + offset = 0; + } + + rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset, + SFP_BLOCK_SIZE); + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Unable to read SFP data (%x/%x/%x).\n", rval, + addr, offset); + count = 0; + break; + } + memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE); + buf += SFP_BLOCK_SIZE; + } + + return count; +} + +static struct bin_attribute sysfs_sfp_attr = { + .attr = { + .name = "sfp", + .mode = S_IRUSR | S_IWUSR, + .owner = THIS_MODULE, + }, + .size = SFP_DEV_SIZE * 2, + .read = qla2x00_sysfs_read_sfp, +}; + void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) { @@ -349,6 +396,9 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); } void @@ -362,6 +412,9 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_sfp_attr); if (ha->beacon_blink_led == 1) ha->isp_ops.beacon_off(ha); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index dfcd3a2dd7c..bb0b5f5e31a 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -610,6 +610,7 @@ typedef struct { #define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ #define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ #define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ +#define MBC_READ_SFP 0x31 /* Read SFP Data. */ #define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ #define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ #define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */ @@ -2242,6 +2243,11 @@ typedef struct scsi_qla_host { struct sns_cmd_pkt *sns_cmd; dma_addr_t sns_cmd_dma; +#define SFP_DEV_SIZE 256 +#define SFP_BLOCK_SIZE 64 + void *sfp_data; + dma_addr_t sfp_data_dma; + struct task_struct *dpc_thread; uint8_t dpc_active; /* DPC routine is active */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index fec1e1c9381..4edb5d11b77 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -210,6 +210,9 @@ qla2x00_stop_firmware(scsi_qla_host_t *); extern int qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t); +extern int +qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t); + /* * Global Function Prototypes in qla_isr.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 3b16d6f2ee9..f5e226fc9e3 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2503,4 +2503,40 @@ qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma, return rval; } +int +qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr, + uint16_t off, uint16_t count) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_READ_SFP; + mcp->mb[1] = addr; + mcp->mb[2] = MSW(sfp_dma); + mcp->mb[3] = LSW(sfp_dma); + mcp->mb[6] = MSW(MSD(sfp_dma)); + mcp->mb[7] = LSW(MSD(sfp_dma)); + mcp->mb[8] = count; + mcp->mb[9] = off; + mcp->mb[10] = 0; + mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 30; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__, + ha->host_no, rval, mcp->mb[0])); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c16154c5129..da84ee2d090 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1979,6 +1979,26 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) continue; } memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt)); + + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + /* + * Get consistent memory allocated for SFP + * block. + */ + ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, + GFP_KERNEL, &ha->sfp_data_dma); + if (ha->sfp_data == NULL) { + qla_printk(KERN_WARNING, ha, + "Memory Allocation failed - " + "sfp_data\n"); + + qla2x00_mem_free(ha); + msleep(100); + + continue; + } + memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); + } } /* Done all allocations without any error. */ @@ -2034,6 +2054,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), ha->ct_sns, ha->ct_sns_dma); + if (ha->sfp_data) + dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); + if (ha->ms_iocb) dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); -- cgit v1.2.3 From 7914d004bcff3e59ca7c0d628f9862fe6655429c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:10:55 -0700 Subject: [SCSI] qla2xxx: Create an VPD sysfs entry for supported ISPs only. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 1a766b284cf..87f90c4f08e 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -294,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Read NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size); @@ -316,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off, if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size) return 0; - if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) - return -ENOTSUPP; - /* Write NVRAM. */ spin_lock_irqsave(&ha->hardware_lock, flags); ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count); @@ -395,10 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_create_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_sfp_attr); + } } void @@ -411,10 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_ctl_attr); - sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr); - if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) + if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { + sysfs_remove_bin_file(&host->shost_gendev.kobj, + &sysfs_vpd_attr); sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_sfp_attr); + } if (ha->beacon_blink_led == 1) ha->isp_ops.beacon_off(ha); -- cgit v1.2.3 From 7469059d52c5f762890cc060ef3f0452c097b91e Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:00 -0700 Subject: [SCSI] qla2xxx: Remove no-op IOCTL codes and macros. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 7 ------- drivers/scsi/qla2xxx/qla_isr.c | 20 -------------------- drivers/scsi/qla2xxx/qla_os.c | 14 -------------- 3 files changed, 41 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 4edb5d11b77..9ff3298405c 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -285,13 +285,6 @@ extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); extern int qla2x00_fdmi_register(scsi_qla_host_t *); -/* - * Global Function Prototypes in qla_xioctl.c source file. - */ -#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0) -#define qla2x00_alloc_ioctl_mem(ha) (0) -#define qla2x00_free_ioctl_mem(ha) do { } while (0) - /* * Global Function Prototypes in qla_attr.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b28ac0a27e2..b9f01f7cb9f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -395,10 +395,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL); - break; case MBA_LOOP_UP: /* Loop Up Event */ @@ -418,9 +414,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) link_speed); ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL); break; case MBA_LOOP_DOWN: /* Loop Down Event */ @@ -439,9 +432,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->link_data_rate = LDR_UNKNOWN; if (ql2xfdmienable) set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); break; case MBA_LIP_RESET: /* LIP reset occurred */ @@ -460,10 +450,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->operating_mode = LOOP; ha->flags.management_server_logged_in = 0; - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL); - break; case MBA_POINT_TO_POINT: /* Point-to-Point */ @@ -545,9 +531,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL); break; case MBA_RSCN_UPDATE: /* State Change Registration */ @@ -584,9 +567,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); set_bit(RSCN_UPDATE, &ha->dpc_flags); - - /* Update AEN queue. */ - qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]); break; /* case MBA_RIO_RESPONSE: */ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index da84ee2d090..0c6e33456f5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1906,17 +1906,6 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha) } memset(ha->init_cb, 0, ha->init_cb_size); - /* Allocate ioctl related memory. */ - if (qla2x00_alloc_ioctl_mem(ha)) { - qla_printk(KERN_WARNING, ha, - "Memory Allocation failed - ioctl_mem\n"); - - qla2x00_mem_free(ha); - msleep(100); - - continue; - } - if (qla2x00_allocate_sp_pool(ha)) { qla_printk(KERN_WARNING, ha, "Memory Allocation failed - " @@ -2033,9 +2022,6 @@ qla2x00_mem_free(scsi_qla_host_t *ha) return; } - /* free ioctl memory */ - qla2x00_free_ioctl_mem(ha); - /* free sp pool */ qla2x00_free_sp_pool(ha); -- cgit v1.2.3 From 744f11fdb1118c9306303529263e5ed09b463a0f Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:05 -0700 Subject: [SCSI] qla2xxx: Cleanup DEBUG macro usage. - macro usage statements should terminate with a ';' - remove unused macros. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.h | 98 +++++++++----------- drivers/scsi/qla2xxx/qla_init.c | 10 +- drivers/scsi/qla2xxx/qla_isr.c | 4 +- drivers/scsi/qla2xxx/qla_mbx.c | 200 ++++++++++++++++++++-------------------- drivers/scsi/qla2xxx/qla_os.c | 8 +- 5 files changed, 154 insertions(+), 166 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index ace6afdfe70..2cea0097fba 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -37,122 +37,110 @@ /* * Macros use for debugging the driver. */ -#undef ENTER_TRACE -#if defined(ENTER_TRACE) -#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0) -#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0) -#else -#define ENTER(x) do {} while (0) -#define LEAVE(x) do {} while (0) -#define ENTER_INTR(x) do {} while (0) -#define LEAVE_INTR(x) do {} while (0) -#endif #if DEBUG_QLA2100 -#define DEBUG(x) do {x;} while (0); +#define DEBUG(x) do {x;} while (0) #else -#define DEBUG(x) do {} while (0); +#define DEBUG(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_1) -#define DEBUG1(x) do {x;} while (0); +#define DEBUG1(x) do {x;} while (0) #else -#define DEBUG1(x) do {} while (0); +#define DEBUG1(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG2_11(x) do {x;} while (0); -#define DEBUG2_13(x) do {x;} while (0); +#define DEBUG2(x) do {x;} while (0) +#define DEBUG2_3(x) do {x;} while (0) +#define DEBUG2_3_11(x) do {x;} while (0) +#define DEBUG2_9_10(x) do {x;} while (0) +#define DEBUG2_11(x) do {x;} while (0) +#define DEBUG2_13(x) do {x;} while (0) #else -#define DEBUG2(x) do {} while (0); +#define DEBUG2(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#define DEBUG2_3_11(x) do {x;} while (0); -#define DEBUG3_11(x) do {x;} while (0); +#define DEBUG3(x) do {x;} while (0) +#define DEBUG2_3(x) do {x;} while (0) +#define DEBUG2_3_11(x) do {x;} while (0) +#define DEBUG3_11(x) do {x;} while (0) #else -#define DEBUG3(x) do {} while (0); +#define DEBUG3(x) do {} while (0) #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_3(x) do {} while (0); + #define DEBUG2_3(x) do {} while (0) #endif #endif #if defined(QL_DEBUG_LEVEL_4) -#define DEBUG4(x) do {x;} while (0); +#define DEBUG4(x) do {x;} while (0) #else -#define DEBUG4(x) do {} while (0); +#define DEBUG4(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_5) -#define DEBUG5(x) do {x;} while (0); +#define DEBUG5(x) do {x;} while (0) #else -#define DEBUG5(x) do {} while (0); +#define DEBUG5(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_7) -#define DEBUG7(x) do {x;} while (0); +#define DEBUG7(x) do {x;} while (0) #else -#define DEBUG7(x) do {} while (0); +#define DEBUG7(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_9) -#define DEBUG9(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); +#define DEBUG9(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) +#define DEBUG2_9_10(x) do {x;} while (0) #else -#define DEBUG9(x) do {} while (0); +#define DEBUG9(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_10) -#define DEBUG10(x) do {x;} while (0); -#define DEBUG2_9_10(x) do {x;} while (0); -#define DEBUG9_10(x) do {x;} while (0); +#define DEBUG10(x) do {x;} while (0) +#define DEBUG2_9_10(x) do {x;} while (0) +#define DEBUG9_10(x) do {x;} while (0) #else -#define DEBUG10(x) do {} while (0); +#define DEBUG10(x) do {} while (0) #if !defined(DEBUG2_9_10) - #define DEBUG2_9_10(x) do {} while (0); + #define DEBUG2_9_10(x) do {} while (0) #endif #if !defined(DEBUG9_10) - #define DEBUG9_10(x) do {} while (0); + #define DEBUG9_10(x) do {} while (0) #endif #endif #if defined(QL_DEBUG_LEVEL_11) -#define DEBUG11(x) do{x;} while(0); +#define DEBUG11(x) do{x;} while(0) #if !defined(DEBUG2_11) -#define DEBUG2_11(x) do{x;} while(0); +#define DEBUG2_11(x) do{x;} while(0) #endif #if !defined(DEBUG2_3_11) -#define DEBUG2_3_11(x) do{x;} while(0); +#define DEBUG2_3_11(x) do{x;} while(0) #endif #if !defined(DEBUG3_11) -#define DEBUG3_11(x) do{x;} while(0); +#define DEBUG3_11(x) do{x;} while(0) #endif #else -#define DEBUG11(x) do{} while(0); +#define DEBUG11(x) do{} while(0) #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_11(x) do{} while(0); + #define DEBUG2_11(x) do{} while(0) #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG2_3_11(x) do{} while(0); + #define DEBUG2_3_11(x) do{} while(0) #endif #endif #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG3_11(x) do{} while(0); + #define DEBUG3_11(x) do{} while(0) #endif #endif #if defined(QL_DEBUG_LEVEL_12) -#define DEBUG12(x) do {x;} while (0); +#define DEBUG12(x) do {x;} while (0) #else -#define DEBUG12(x) do {} while (0); +#define DEBUG12(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_13) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 2ccdd848bcf..101cf12b9a4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3137,14 +3137,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) ha->isp_abort_cnt--; DEBUG(printk("qla%ld: ISP abort - " "retry remaining %d\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); status = 1; } } else { ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; DEBUG(printk("qla2x00(%ld): ISP error recovery " "- retrying (%d) more times\n", - ha->host_no, ha->isp_abort_cnt);) + ha->host_no, ha->isp_abort_cnt)); set_bit(ISP_ABORT_RETRY, &ha->dpc_flags); status = 1; } @@ -3158,7 +3158,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha) } else { DEBUG(printk(KERN_INFO "qla2x00_abort_isp(%ld): exiting.\n", - ha->host_no);) + ha->host_no)); } return(status); @@ -3234,7 +3234,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags); if (!(status = qla2x00_fw_ready(ha))) { DEBUG(printk("%s(): Start configure loop, " - "status = %d\n", __func__, status);) + "status = %d\n", __func__, status)); /* Issue a marker after FW becomes ready. */ qla2x00_marker(ha, 0, 0, MK_SYNC_ALL); @@ -3258,7 +3258,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha) DEBUG(printk("%s(): Configure loop done, status = 0x%x\n", __func__, - status);) + status)); } return (status); } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b9f01f7cb9f..795bf15b1b8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1432,8 +1432,8 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt) DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n", __func__, ha->host_no, pkt, pkt->handle)); - DEBUG9(printk("%s: ct pkt dump:\n", __func__);) - DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx));) + DEBUG9(printk("%s: ct pkt dump:\n", __func__)); + DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx))); /* Validate handle. */ if (pkt->handle < MAX_OUTSTANDING_COMMANDS) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index f5e226fc9e3..879f281e2ea 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -13,13 +13,13 @@ qla2x00_mbx_sem_timeout(unsigned long data) { struct semaphore *sem_ptr = (struct semaphore *)data; - DEBUG11(printk("qla2x00_sem_timeout: entered.\n");) + DEBUG11(printk("qla2x00_sem_timeout: entered.\n")); if (sem_ptr != NULL) { up(sem_ptr); } - DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");) + DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n")); } /* @@ -61,7 +61,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) rval = QLA_SUCCESS; abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); /* * Wait for active mailbox commands to finish by waiting at most tov @@ -72,7 +72,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) { /* Timeout occurred. Return error. */ DEBUG2_3_11(printk("%s(%ld): cmd access timeout. " - "Exiting.\n", __func__, ha->host_no);) + "Exiting.\n", __func__, ha->host_no)); return QLA_FUNCTION_TIMEOUT; } } @@ -86,7 +86,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags); DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); spin_lock_irqsave(&ha->hardware_lock, flags); @@ -131,14 +131,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) /* Unlock mbx registers and wait for interrupt */ DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. " - "jiffies=%lx.\n", __func__, ha->host_no, jiffies);) + "jiffies=%lx.\n", __func__, ha->host_no, jiffies)); /* Wait for mbx cmd completion until timeout */ if (!abort_active && io_lock_on) { /* sleep on completion semaphore */ DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n", - __func__, ha->host_no);) + __func__, ha->host_no)); init_timer(&tmp_intr_timer); tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem; @@ -147,11 +147,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) (void (*)(unsigned long))qla2x00_mbx_sem_timeout; DEBUG11(printk("%s(%ld): Adding timer.\n", __func__, - ha->host_no);) + ha->host_no)); add_timer(&tmp_intr_timer); DEBUG11(printk("%s(%ld): going to unlock & sleep. " - "time=0x%lx.\n", __func__, ha->host_no, jiffies);) + "time=0x%lx.\n", __func__, ha->host_no, jiffies)); set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); @@ -170,14 +170,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) down(&ha->mbx_intr_sem); DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__, - ha->host_no, jiffies);) + ha->host_no, jiffies)); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); /* delete the timer */ del_timer(&tmp_intr_timer); } else { DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); @@ -209,7 +209,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) uint16_t *iptr2; DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__, - ha->host_no, command);) + ha->host_no, command)); /* Got interrupt. Clear the flag. */ ha->flags.mbox_int = 0; @@ -266,7 +266,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!abort_active) { DEBUG11(printk("%s(%ld): checking for additional resp " - "interrupt.\n", __func__, ha->host_no);) + "interrupt.\n", __func__, ha->host_no)); /* polling mode for non isp_abort commands. */ qla2x00_poll(ha); @@ -277,9 +277,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (!io_lock_on || (mcp->flags & IOCTL_CMD)) { /* not in dpc. schedule it for dpc to take over. */ DEBUG(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout schedule " - "isp_abort_needed.\n", __func__, ha->host_no);) + "isp_abort_needed.\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Scheduling ISP " "abort.\n"); @@ -288,9 +288,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } else if (!abort_active) { /* call abort directly since we are in the DPC thread */ DEBUG(printk("%s(%ld): timeout calling abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); DEBUG2_3_11(printk("%s(%ld): timeout calling " - "abort_isp\n", __func__, ha->host_no);) + "abort_isp\n", __func__, ha->host_no)); qla_printk(KERN_WARNING, ha, "Mailbox command timeout occured. Issuing ISP " "abort.\n"); @@ -303,9 +303,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) } clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags); DEBUG(printk("%s(%ld): finished abort_isp\n", __func__, - ha->host_no);) + ha->host_no)); DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n", - __func__, ha->host_no);) + __func__, ha->host_no)); } } @@ -316,9 +316,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) if (rval) { DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, " "mbx2=%x, cmd=%x ****\n", __func__, ha->host_no, - mcp->mb[0], mcp->mb[1], mcp->mb[2], command);) + mcp->mb[0], mcp->mb[1], mcp->mb[2], command)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -394,7 +394,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_EXECUTE_FIRMWARE; mcp->out_mb = MBX_0; @@ -424,10 +424,10 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr) } else { if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { DEBUG11(printk("%s(%ld): done exchanges=%x.\n", - __func__, ha->host_no, mcp->mb[1]);) + __func__, ha->host_no, mcp->mb[1])); } else { DEBUG11(printk("%s(%ld): done.\n", __func__, - ha->host_no);) + ha->host_no)); } } @@ -611,7 +611,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; mcp->mb[1] = 0xAAAA; @@ -639,11 +639,11 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -671,7 +671,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_VERIFY_CHECKSUM; mcp->out_mb = MBX_0; @@ -694,9 +694,9 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__, ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ? - (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));) + (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]))); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -743,9 +743,9 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sts_entry_t *sts_entry = (sts_entry_t *) buffer; @@ -781,7 +781,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no)); fcport = sp->fcport; @@ -813,11 +813,11 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { sp->flags |= SRB_ABORT_PENDING; DEBUG11(printk("qla2x00_abort_command(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -848,7 +848,7 @@ qla2x00_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; mcp->mb[0] = MBC_ABORT_TARGET; @@ -872,11 +872,11 @@ qla2x00_abort_target(fc_port_t *fcport) if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_abort_target(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -912,7 +912,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; mcp->out_mb = MBX_0; @@ -933,11 +933,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -968,7 +968,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_RETRY_COUNT; mcp->out_mb = MBX_0; @@ -980,7 +980,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n", - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { /* Convert returned data and check our values. */ *r_a_tov = mcp->mb[3] / 2; @@ -992,7 +992,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov, } DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d " - "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);) + "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov)); } return rval; @@ -1023,7 +1023,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; mcp->mb[2] = MSW(ha->init_cb_dma); @@ -1043,11 +1043,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size) /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x " "mb0=%x.\n", - ha->host_no, rval, mcp->mb[0]);) + ha->host_no, rval, mcp->mb[0])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1079,7 +1079,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) struct port_database_24xx *pd24; dma_addr_t pd_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); pd24 = NULL; pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); @@ -1220,7 +1220,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_FIRMWARE_STATE; mcp->out_mb = MBX_0; @@ -1235,11 +1235,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): " - "failed=%x.\n", ha->host_no, rval);) + "failed=%x.\n", ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1272,7 +1272,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_GET_PORT_NAME; mcp->out_mb = MBX_1|MBX_0; @@ -1292,7 +1292,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { if (name != NULL) { /* This function returns name in big endian. */ @@ -1307,7 +1307,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name, } DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1335,7 +1335,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; @@ -1364,10 +1364,10 @@ qla2x00_lip_reset(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return rval; @@ -1400,10 +1400,10 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n", - ha->host_no);) + ha->host_no)); DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total " - "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);) + "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov)); mcp->mb[0] = MBC_SEND_SNS_COMMAND; mcp->mb[1] = cmd_size; @@ -1421,12 +1421,12 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x " - "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);) + "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1])); } else { /*EMPTY*/ - DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);) + DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no)); } return rval; @@ -1442,7 +1442,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, dma_addr_t lg_dma; uint32_t iop[2]; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1466,7 +1466,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1507,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, break; } } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); iop[0] = le32_to_cpu(lg->io_parameter[0]); @@ -1561,7 +1561,7 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);) + DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no)); mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -1606,11 +1606,11 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x " "mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[2]);) + mcp->mb[0], mcp->mb[1], mcp->mb[2])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1645,7 +1645,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, mb_ret, opt); - DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no)); mcp->mb[0] = MBC_LOGIN_LOOP_PORT; if (HAS_EXTENDED_IDS(ha)) @@ -1679,13 +1679,13 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport, DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x " "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval, - mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);) + mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7])); } else { /*EMPTY*/ - DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no)); } return (rval); @@ -1699,7 +1699,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, struct logio_entry_24xx *lg; dma_addr_t lg_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -1720,7 +1720,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else if (lg->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -1731,10 +1731,10 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, "-- completion status (%x) ioparam=%x/%x.\n", __func__, ha->host_no, le16_to_cpu(lg->comp_status), le32_to_cpu(lg->io_parameter[0]), - le32_to_cpu(lg->io_parameter[1]));) + le32_to_cpu(lg->io_parameter[1]))); } else { /*EMPTY*/ - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1767,7 +1767,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; mcp->out_mb = MBX_1|MBX_0; @@ -1787,11 +1787,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x " - "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);) + "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1])); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1820,7 +1820,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", - ha->host_no);) + ha->host_no)); mcp->mb[0] = MBC_LIP_FULL_LOGIN; mcp->mb[1] = 0; @@ -1835,11 +1835,11 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha) if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { /*EMPTY*/ DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1866,7 +1866,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, mbx_cmd_t *mcp = &mc; DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n", - ha->host_no);) + ha->host_no)); if (id_list == NULL) return QLA_FUNCTION_FAILED; @@ -1895,11 +1895,11 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n", - ha->host_no, rval);) + ha->host_no, rval)); } else { *entries = mcp->mb[1]; DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n", - ha->host_no);) + ha->host_no)); } return rval; @@ -1938,7 +1938,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt, if (rval != QLA_SUCCESS) { /*EMPTY*/ DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__, - ha->host_no, mcp->mb[0]);) + ha->host_no, mcp->mb[0])); } else { DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x " "mb7=%x mb10=%x.\n", __func__, ha->host_no, @@ -2047,7 +2047,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, link_stat_t *stat_buf; dma_addr_t stat_buf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma); if (stat_buf == NULL) { @@ -2085,7 +2085,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, if (rval == QLA_SUCCESS) { if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n", - __func__, ha->host_no, mcp->mb[0]);) + __func__, ha->host_no, mcp->mb[0])); status[0] = mcp->mb[0]; rval = BIT_1; } else { @@ -2110,12 +2110,12 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id, stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt, stat_buf->prim_seq_err_cnt, stat_buf->inval_xmit_word_cnt, - stat_buf->inval_crc_cnt);) + stat_buf->inval_crc_cnt)); } } else { /* Failed. */ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, - ha->host_no, rval);) + ha->host_no, rval)); rval = BIT_1; } @@ -2134,7 +2134,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords, uint32_t *sbuf, *siter; dma_addr_t sbuf_dma; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); if (dwords > (DMA_POOL_SIZE / 4)) { DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs " @@ -2198,7 +2198,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) dma_addr_t abt_dma; uint32_t handle; - DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); fcport = sp->fcport; @@ -2231,7 +2231,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n", - __func__, ha->host_no, rval);) + __func__, ha->host_no, rval)); } else if (abt->entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- error status (%x).\n", __func__, ha->host_no, @@ -2240,10 +2240,10 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp) } else if (abt->nport_handle != __constant_cpu_to_le16(0)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, ha->host_no, - le16_to_cpu(abt->nport_handle));) + le16_to_cpu(abt->nport_handle))); rval = QLA_FUNCTION_FAILED; } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); sp->flags |= SRB_ABORT_PENDING; } @@ -2270,7 +2270,7 @@ qla24xx_abort_target(fc_port_t *fcport) if (fcport == NULL) return 0; - DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);) + DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no)); ha = fcport->ha; tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); @@ -2292,7 +2292,7 @@ qla24xx_abort_target(fc_port_t *fcport) rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); goto atarget_done; } else if (tsk->p.sts.entry_status != 0) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " @@ -2304,7 +2304,7 @@ qla24xx_abort_target(fc_port_t *fcport) __constant_cpu_to_le16(CS_COMPLETE)) { DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB " "-- completion status (%x).\n", __func__, - ha->host_no, le16_to_cpu(tsk->p.sts.comp_status));) + ha->host_no, le16_to_cpu(tsk->p.sts.comp_status))); rval = QLA_FUNCTION_FAILED; goto atarget_done; } @@ -2313,9 +2313,9 @@ qla24xx_abort_target(fc_port_t *fcport) rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID); if (rval != QLA_SUCCESS) { DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB " - "(%x).\n", __func__, ha->host_no, rval);) + "(%x).\n", __func__, ha->host_no, rval)); } else { - DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);) + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); } atarget_done: diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0c6e33456f5..fedf2f17808 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -631,7 +631,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n", __func__, ha->host_no, sp, serial)); - DEBUG3(qla2x00_print_scsi_cmd(cmd);) + DEBUG3(qla2x00_print_scsi_cmd(cmd)); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (ha->isp_ops.abort_command(ha, sp)) { @@ -773,7 +773,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) #endif } else { DEBUG2(printk(KERN_INFO - "%s failed: loop not ready\n",__func__);) + "%s failed: loop not ready\n",__func__)); } if (ret == FAILED) { @@ -1028,12 +1028,12 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) /* Empty */ DEBUG2_3(printk("%s(%ld): **** FAILED ****\n", __func__, - ha->host_no);) + ha->host_no)); } else { /* Empty */ DEBUG3(printk("%s(%ld): exiting normally.\n", __func__, - ha->host_no);) + ha->host_no)); } return(status); -- cgit v1.2.3 From 0181944fe647cae18d545ac1167df3d15d393701 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:10 -0700 Subject: [SCSI] qla2xxx: Add support for extended error logging. Similar in form to QLogic's standard offering -- via the 'extended_error_logging' module parameter. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.h | 50 ++++++----------------------------------- drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 2 ++ drivers/scsi/qla2xxx/qla_os.c | 12 +++++++--- 4 files changed, 19 insertions(+), 46 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index 2cea0097fba..533425338e0 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -38,11 +38,7 @@ * Macros use for debugging the driver. */ -#if DEBUG_QLA2100 -#define DEBUG(x) do {x;} while (0) -#else -#define DEBUG(x) do {} while (0) -#endif +#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_1) #define DEBUG1(x) do {x;} while (0) @@ -50,27 +46,18 @@ #define DEBUG1(x) do {} while (0) #endif -#if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {x;} while (0) -#define DEBUG2_3(x) do {x;} while (0) -#define DEBUG2_3_11(x) do {x;} while (0) -#define DEBUG2_9_10(x) do {x;} while (0) -#define DEBUG2_11(x) do {x;} while (0) -#define DEBUG2_13(x) do {x;} while (0) -#else -#define DEBUG2(x) do {} while (0) -#endif +#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0) +#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0) #if defined(QL_DEBUG_LEVEL_3) #define DEBUG3(x) do {x;} while (0) -#define DEBUG2_3(x) do {x;} while (0) -#define DEBUG2_3_11(x) do {x;} while (0) #define DEBUG3_11(x) do {x;} while (0) #else #define DEBUG3(x) do {} while (0) - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_3(x) do {} while (0) - #endif #endif #if defined(QL_DEBUG_LEVEL_4) @@ -94,20 +81,15 @@ #if defined(QL_DEBUG_LEVEL_9) #define DEBUG9(x) do {x;} while (0) #define DEBUG9_10(x) do {x;} while (0) -#define DEBUG2_9_10(x) do {x;} while (0) #else #define DEBUG9(x) do {} while (0) #endif #if defined(QL_DEBUG_LEVEL_10) #define DEBUG10(x) do {x;} while (0) -#define DEBUG2_9_10(x) do {x;} while (0) #define DEBUG9_10(x) do {x;} while (0) #else #define DEBUG10(x) do {} while (0) - #if !defined(DEBUG2_9_10) - #define DEBUG2_9_10(x) do {} while (0) - #endif #if !defined(DEBUG9_10) #define DEBUG9_10(x) do {} while (0) #endif @@ -115,23 +97,11 @@ #if defined(QL_DEBUG_LEVEL_11) #define DEBUG11(x) do{x;} while(0) -#if !defined(DEBUG2_11) -#define DEBUG2_11(x) do{x;} while(0) -#endif -#if !defined(DEBUG2_3_11) -#define DEBUG2_3_11(x) do{x;} while(0) -#endif #if !defined(DEBUG3_11) #define DEBUG3_11(x) do{x;} while(0) #endif #else #define DEBUG11(x) do{} while(0) - #if !defined(QL_DEBUG_LEVEL_2) - #define DEBUG2_11(x) do{} while(0) - #if !defined(QL_DEBUG_LEVEL_3) - #define DEBUG2_3_11(x) do{} while(0) - #endif - #endif #if !defined(QL_DEBUG_LEVEL_3) #define DEBUG3_11(x) do{} while(0) #endif @@ -145,14 +115,8 @@ #if defined(QL_DEBUG_LEVEL_13) #define DEBUG13(x) do {x;} while (0) -#if !defined(DEBUG2_13) -#define DEBUG2_13(x) do {x;} while(0) -#endif #else #define DEBUG13(x) do {} while (0) -#if !defined(QL_DEBUG_LEVEL_2) -#define DEBUG2_13(x) do {} while(0) -#endif #endif #if defined(QL_DEBUG_LEVEL_14) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 9ff3298405c..750aef11c2e 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -64,6 +64,7 @@ extern int ql2xplogiabsentdevice; extern int ql2xloginretrycount; extern int ql2xfdmienable; extern int ql2xallocfwdump; +extern int extended_error_logging; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 101cf12b9a4..761dd1f7e3f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1642,6 +1642,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) /* * Set host adapter parameters. */ + if (nv->host_p[0] & BIT_7) + extended_error_logging = 1; ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); /* Always load RISC code on non ISP2[12]00 chips. */ if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fedf2f17808..a15b6090813 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -61,6 +61,12 @@ MODULE_PARM_DESC(ql2xallocfwdump, "during HBA initialization. Memory allocation requirements " "vary by ISP type. Default is 1 - allocate memory."); +int extended_error_logging; +module_param(extended_error_logging, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(extended_error_logging, + "Option to enable extended error logging, " + "Default is 0 - no logging. 1 - log errors."); + static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); @@ -2691,9 +2697,9 @@ qla2x00_module_init(void) /* Derive version string. */ strcpy(qla2x00_version_str, QLA2XXX_VERSION); -#if DEBUG_QLA2100 - strcat(qla2x00_version_str, "-debug"); -#endif + if (extended_error_logging) + strcat(qla2x00_version_str, "-debug"); + qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) -- cgit v1.2.3 From 7d7abc77cc469ff41dde8eea606e1dab88d4ba86 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:17 -0700 Subject: [SCSI] qla2xxx: Correct 'loop-down' determination logic in qla2x00_fw_ready(). As there is no point in failing the initialization process when firmware informs the host software that it could not transition beyond a CONFIG_WAIT nor WAIT_FOR_LOGIN state. Previous logic would mark such conditions as a general *failure* and subsequently tear-down the scsi-host during initialization. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 761dd1f7e3f..c7ab66877fb 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1273,8 +1273,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha) rval = QLA_FUNCTION_FAILED; if (atomic_read(&ha->loop_down_timer) && - (fw_state >= FSTATE_LOSS_OF_SYNC || - fw_state == FSTATE_WAIT_AL_PA)) { + fw_state != FSTATE_READY) { /* Loop down. Timeout on min_wait for states * other than Wait for Login. */ -- cgit v1.2.3 From 7ee613970947bdf5f722bb01547c97f4fc80fe9f Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:22 -0700 Subject: [SCSI] qla2xxx: Convert from pci_module_init() to pci_register_driver(). Also remove qla2xxx_probe_one/qla2xxx_remove_one stubs previously used with external firmware module loaders. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a15b6090813..3516e36107b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1337,7 +1337,8 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha) /* * PCI driver interface */ -static int qla2x00_probe_one(struct pci_dev *pdev) +static int __devinit +qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { int ret = -ENODEV; device_reg_t __iomem *reg; @@ -1650,7 +1651,8 @@ probe_out: return ret; } -static void qla2x00_remove_one(struct pci_dev *pdev) +static void __devexit +qla2x00_remove_one(struct pci_dev *pdev) { scsi_qla_host_t *ha; @@ -2644,40 +2646,16 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); -static int __devinit -qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - return qla2x00_probe_one(pdev); -} - -static void __devexit -qla2xxx_remove_one(struct pci_dev *pdev) -{ - qla2x00_remove_one(pdev); -} - static struct pci_driver qla2xxx_pci_driver = { .name = QLA2XXX_DRIVER_NAME, .driver = { .owner = THIS_MODULE, }, .id_table = qla2xxx_pci_tbl, - .probe = qla2xxx_probe_one, - .remove = __devexit_p(qla2xxx_remove_one), + .probe = qla2x00_probe_one, + .remove = __devexit_p(qla2x00_remove_one), }; -static inline int -qla2x00_pci_module_init(void) -{ - return pci_module_init(&qla2xxx_pci_driver); -} - -static inline void -qla2x00_pci_module_exit(void) -{ - pci_unregister_driver(&qla2xxx_pci_driver); -} - /** * qla2x00_module_init - Module initialization. **/ @@ -2706,7 +2684,7 @@ qla2x00_module_init(void) return -ENODEV; printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n"); - ret = qla2x00_pci_module_init(); + ret = pci_register_driver(&qla2xxx_pci_driver); if (ret) { kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); @@ -2720,7 +2698,7 @@ qla2x00_module_init(void) static void __exit qla2x00_module_exit(void) { - qla2x00_pci_module_exit(); + pci_unregister_driver(&qla2xxx_pci_driver); qla2x00_release_firmware(); kmem_cache_destroy(srb_cachep); fc_release_transport(qla2xxx_transport_template); -- cgit v1.2.3 From 3ea66e28c20e3b23749c9001c58b37ad44263442 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:27 -0700 Subject: [SCSI] qla2xxx: Correctly set the firmware NOS/OLS timeout during initialization. Original code incorrectly assigned it to the driver's link-down-timeout value (a value in seconds). Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_fw.h | 2 +- drivers/scsi/qla2xxx/qla_init.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index af023f51fe7..a0a722cf423 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -278,7 +278,7 @@ struct init_cb_24xx { uint16_t response_q_length; uint16_t request_q_length; - uint16_t link_down_timeout; /* Milliseconds. */ + uint16_t link_down_on_nos; /* Milliseconds. */ uint16_t prio_request_q_length; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index c7ab66877fb..ce32322f1e1 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3379,7 +3379,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) nv->node_name[6] = 0x55; nv->node_name[7] = 0x86; nv->login_retry_count = __constant_cpu_to_le16(8); - nv->link_down_timeout = __constant_cpu_to_le16(200); nv->interrupt_delay_timer = __constant_cpu_to_le16(0); nv->login_timeout = __constant_cpu_to_le16(0); nv->firmware_options_1 = @@ -3408,7 +3407,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) *dptr1++ = *dptr2++; icb->login_retry_count = nv->login_retry_count; - icb->link_down_timeout = nv->link_down_timeout; + icb->link_down_on_nos = nv->link_down_on_nos; /* Copy 2nd segment. */ dptr1 = (uint8_t *)&icb->interrupt_delay_timer; -- cgit v1.2.3 From 76c1534e0bd78e9a7662edcf5c994bac63d939fd Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 23 Jun 2006 16:11:32 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.01.05-k3. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 6b315521bd8..d2d68344065 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.05-k2" +#define QLA2XXX_VERSION "8.01.05-k3" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 -- cgit v1.2.3 From 041976fb6ae851cd18d96584a5d6361b564c9974 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 25 Jun 2006 01:58:51 -0700 Subject: [SCSI] lpfc: sparse NULL warnings From: Randy Dunlap Fix sparse warnings: use NULL instead of 0 for pointers: drivers/scsi/lpfc/lpfc_els.c:827:56: warning: Using plain integer as NULL pointer drivers/scsi/lpfc/lpfc_els.c:2781:18: warning: Using plain integer as NULL pointer drivers/scsi/lpfc/lpfc_els.c:2782:18: warning: Using plain integer as NULL pointer drivers/scsi/lpfc/lpfc_init.c:951:21: warning: Using plain integer as NULL pointer drivers/scsi/lpfc/lpfc_init.c:956:20: warning: Using plain integer as NULL pointer Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_els.c | 6 +++--- drivers/scsi/lpfc/lpfc_init.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 283b7d824c3..4126fd87956 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -821,7 +821,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry) pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did, + elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -2791,8 +2791,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp = (struct lpfc_nodelist *) pmb->context2; xri = (uint16_t) ((unsigned long)(pmb->context1)); - pmb->context1 = 0; - pmb->context2 = 0; + pmb->context1 = NULL; + pmb->context2 = NULL; if (mb->mbxStatus) { mempool_free( pmb, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 908d0f27706..c8db857ffb3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -939,12 +939,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp) "10-port ", "PCIe"}; break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } break; default: - m = (typeof(m)){ 0 }; + m = (typeof(m)){ NULL }; break; } -- cgit v1.2.3 From 3e7196cf6070821ff8246b15dfd219ffa6409062 Mon Sep 17 00:00:00 2001 From: GOTO Masanori Date: Sun, 25 Jun 2006 01:58:56 -0700 Subject: [SCSI] Add scsi_add_host() failure handling for nsp32 Add scsi_add_host() failure handling for nsp32 and silence warning. drivers/scsi/nsp32.c:2888: warning: ignoring return value of 'Scsi_add_host', declared with attribute warn_unused_result Signed-off-by: Jesper Juhl Signed-off-by: GOTO Masanori Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/nsp32.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 5c55e152e71..159fd5d8f98 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -2886,12 +2886,19 @@ static int nsp32_detect(struct scsi_host_template *sht) } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) - scsi_add_host (host, &PCIDEV->dev); + ret = scsi_add_host(host, &PCIDEV->dev); + if (ret) { + nsp32_msg(KERN_ERR, "failed to add scsi host"); + goto free_region; + } scsi_scan_host(host); #endif pci_set_drvdata(PCIDEV, host); return DETECT_OK; + free_region: + release_region(host->io_port, host->n_io_port); + free_irq: free_irq(host->irq, data); -- cgit v1.2.3 From 8d55a786febd077f3a0db9f0672dfa1288b452af Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Sun, 25 Jun 2006 01:58:58 -0700 Subject: [SCSI] Bogus disk geometry on large disks We currently stuff a truncated size into the geometry logic and return the result which can produce bizarre reports for a 4Tb array. Since that mapping logic isn't useful for disks that big don't try and map this way at all. Signed-off-by: Alan Cox Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsicam.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index b78354fc4b1..cd68a66c7bb 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable); int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) { unsigned char *p; + u64 capacity64 = capacity; /* Suppress gcc warning */ int ret; p = scsi_bios_ptable(bdev); @@ -68,7 +69,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) (unsigned int *)ip + 0, (unsigned int *)ip + 1); kfree(p); - if (ret == -1) { + if (ret == -1 && capacity64 < (1ULL << 32)) { /* pick some standard mapping with at most 1024 cylinders, and at most 62 sectors per track - this works up to 7905 MB */ -- cgit v1.2.3 From 99d19bb75b88cc997d3cd611903908714c735981 Mon Sep 17 00:00:00 2001 From: Matt Mackall Date: Sun, 25 Jun 2006 01:58:54 -0700 Subject: [SCSI] random: remove redundant SA_SAMPLE_RANDOM from NinjaSCSI The scsi layer is already calling add_disk_randomness in scsi_end_request. Signed-off-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/nsp32.c | 3 +-- drivers/scsi/pcmcia/nsp_cs.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 159fd5d8f98..4190788f14b 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -2866,8 +2866,7 @@ static int nsp32_detect(struct scsi_host_template *sht) */ nsp32_do_bus_reset(data); - ret = request_irq(host->irq, do_nsp32_isr, - SA_SHIRQ | SA_SAMPLE_RANDOM, "nsp32", data); + ret = request_irq(host->irq, do_nsp32_isr, SA_SHIRQ, "nsp32", data); if (ret < 0) { nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 " "SCSI PCI controller. Interrupt: %d", host->irq); diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 231f9c311c6..bb81218b8d1 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -1623,7 +1623,7 @@ static int nsp_cs_probe(struct pcmcia_device *link) /* Interrupt handler */ link->irq.Handler = &nspintr; link->irq.Instance = info; - link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM); + link->irq.Attributes |= SA_SHIRQ; /* General socket configuration */ link->conf.Attributes = CONF_ENABLE_IRQ; -- cgit v1.2.3 From 12e9b5fb96028aab26af65bb06d2dee56c428a6e Mon Sep 17 00:00:00 2001 From: "Salyzyn, Mark" Date: Mon, 26 Jun 2006 08:37:39 -0400 Subject: [SCSI] aacraid: remove x86_64 IOMMU dependent code This may seem like a DILLIGAF, but after chatting with the F/W folks, there is no harm in dropping the page calculation as denoted in the enclosed patch for these older adapters in this new age of 4GB+ memory sticks. Any resource optimization within the old-old-old adapters for systems with less than 4G of memory is of little consequence. The existing AAC_QUIRK_31BIT flag in linit.c should look after the rest of the legacy hardware DMA limitations. Signed-off-by: Mark Salyzyn Signed-off-by: James Bottomley --- drivers/scsi/aacraid/comminit.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 35b0a6ebd3f..1cd3584ba7f 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -92,28 +92,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); init->AdapterFibsSize = cpu_to_le32(fibsize); init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - /* - * number of 4k pages of host physical memory. The aacraid fw needs - * this number to be less than 4gb worth of pages. num_physpages is in - * system page units. New firmware doesn't have any issues with the - * mapping system, but older Firmware did, and had *troubles* dealing - * with the math overloading past 32 bits, thus we must limit this - * field. - * - * This assumes the memory is mapped zero->n, which isnt - * always true on real computers. It also has some slight problems - * with the GART on x86-64. I've btw never tried DMA from PCI space - * on this platform but don't be surprised if its problematic. - */ -#ifndef CONFIG_GART_IOMMU - if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) { - init->HostPhysMemPages = - cpu_to_le32(num_physpages << (PAGE_SHIFT-12)); - } else -#endif - { - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); - } + init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); init->InitFlags = 0; if (dev->new_comm_interface) { -- cgit v1.2.3 From d7a1bb0a04ca835bffc0a91e64ab827dfba7d8f5 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 8 Mar 2006 14:50:12 -0500 Subject: [SCSI] Block I/O while SG reset operation in progress - the midlayer patch The scsi midlayer portion of the patch Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 22 ++++++++++++++++++++++ include/scsi/scsi_host.h | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 6a7a60fc0a4..6683d596234 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1672,7 +1672,9 @@ int scsi_reset_provider(struct scsi_device *dev, int flag) { struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL); + struct Scsi_Host *shost = dev->host; struct request req; + unsigned long flags; int rtn; scmd->request = &req; @@ -1699,6 +1701,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag) */ scmd->pid = 0; + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 1; + spin_unlock_irqrestore(shost->host_lock, flags); + switch (flag) { case SCSI_TRY_RESET_DEVICE: rtn = scsi_try_bus_device_reset(scmd); @@ -1717,6 +1723,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag) rtn = FAILED; } + spin_lock_irqsave(shost->host_lock, flags); + shost->tmf_in_progress = 0; + spin_unlock_irqrestore(shost->host_lock, flags); + + /* + * be sure to wake up anyone who was sleeping or had their queue + * suspended while we performed the TMF. + */ + SCSI_LOG_ERROR_RECOVERY(3, + printk("%s: waking up host to restart after TMF\n", + __FUNCTION__)); + + wake_up(&shost->host_wait); + + scsi_run_host_queues(shost); + scsi_next_command(scmd); return rtn; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index a42efd6e4be..b3dd90f3e85 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -542,6 +542,9 @@ struct Scsi_Host { */ unsigned ordered_tag:1; + /* task mgmt function in progress */ + unsigned tmf_in_progress:1; + /* * Optional work queue to be utilized by the transport */ @@ -619,7 +622,8 @@ static inline int scsi_host_in_recovery(struct Scsi_Host *shost) { return shost->shost_state == SHOST_RECOVERY || shost->shost_state == SHOST_CANCEL_RECOVERY || - shost->shost_state == SHOST_DEL_RECOVERY; + shost->shost_state == SHOST_DEL_RECOVERY || + shost->tmf_in_progress; } extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); -- cgit v1.2.3 From 79ac6745e4d95cd583bca744d313a323deb4adc2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Wed, 8 Mar 2006 14:50:18 -0500 Subject: [SCSI] Block I/O while SG reset operation in progress - lpfc portion This removes the duplicate functionality which had been added to the lpfc driver. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 1 - drivers/scsi/lpfc/lpfc_init.c | 1 - drivers/scsi/lpfc/lpfc_scsi.c | 20 -------------------- 3 files changed, 22 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 087c44539a1..f81691fcf17 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -174,7 +174,6 @@ struct lpfc_hba { dma_addr_t slim2p_mapping; uint16_t pci_cfg_value; - struct semaphore hba_can_block; int32_t hba_state; #define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */ diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index c8db857ffb3..f68ad765498 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1451,7 +1451,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) goto out_put_host; host->unique_id = phba->brd_no; - init_MUTEX(&phba->hba_can_block); INIT_LIST_HEAD(&phba->ctrspbuflist); INIT_LIST_HEAD(&phba->rnidrspbuflist); INIT_LIST_HEAD(&phba->freebufList); diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7dc4c2e6bed..aea1ee472f3 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -41,20 +41,6 @@ #define LPFC_ABORT_WAIT 2 -static inline void -lpfc_block_requests(struct lpfc_hba * phba) -{ - down(&phba->hba_can_block); - scsi_block_requests(phba->host); -} - -static inline void -lpfc_unblock_requests(struct lpfc_hba * phba) -{ - scsi_unblock_requests(phba->host); - up(&phba->hba_can_block); -} - /* * This routine allocates a scsi buffer, which contains all the necessary * information needed to initiate a SCSI I/O. The non-DMAable buffer region @@ -859,7 +845,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) unsigned int loop_count = 0; int ret = SUCCESS; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; @@ -945,7 +930,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) cmnd->device->lun, cmnd->serial_number); spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -963,7 +947,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd) int ret = FAILED; int cnt, loopcnt; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); /* * If target is not in a MAPPED state, delay the reset until @@ -1065,7 +1048,6 @@ out_free_scsi_buf: out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } @@ -1080,7 +1062,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) int cnt, loopcnt; struct lpfc_scsi_buf * lpfc_cmd; - lpfc_block_requests(phba); spin_lock_irq(shost->host_lock); lpfc_cmd = lpfc_get_scsi_buf(phba); @@ -1163,7 +1144,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd) phba->brd_no, ret); out: spin_unlock_irq(shost->host_lock); - lpfc_unblock_requests(phba); return ret; } -- cgit v1.2.3 From a0785edff7b316cad566bdc369d3d034c4c1a39c Mon Sep 17 00:00:00 2001 From: James Smart Date: Thu, 11 May 2006 13:27:09 -0400 Subject: [SCSI] fc transport: resolve scan vs delete deadlocks In a prior posting to linux-scsi on the fc transport and workq deadlocks, we noted a second error that did not have a patch: http://marc.theaimsgroup.com/?l=linux-scsi&m=114467847711383&w=2 - There's a deadlock where scsi_remove_target() has to sit behind scsi_scan_target() due to contention over the scan_lock(). Subsequently we posted a request for comments about the deadlock: http://marc.theaimsgroup.com/?l=linux-scsi&m=114469358829500&w=2 This posting resolves the second error. Here's what we now understand, and are implementing: If the lldd deletes the rport while a scan is active, the sdev's queue is blocked which stops the issuing of commands associated with the scan. At this point, the scan stalls, and does so with the shost->scan_mutex held. If, at this point, if any scan or delete request is made on the host, it will stall waiting for the scan_mutex. For the FC transport, we queue all delete work to a single workq. So, things worked fine when competing with the scan, as long as the target blocking the scan was the same target at the top of our delete workq, as the delete workq routine always unblocked just prior to requesting the delete. Unfortunately, if the top of our delete workq was for a different target, we deadlock. Additionally, if the target blocking scan returned, we were unblocking it in the scan workq routine, which really won't execute until the existing stalled scan workq completes (e.g. we're re-scheduling it while it is in the midst of its execution). This patch moves the unblock out of the workq routines and moves it to the context that is scheduling the work. This ensures that at some point, we will unblock the target that is blocking scan. Please note, however, that the deadlock condition may still occur while it waits for the transport to timeout an unblock on a target. Worst case, this is bounded by the transport dev_loss_tmo (default: 30 seconds). Finally, Michael Reed deserves the credit for the bulk of this patch, analysis, and it's testing. Thank you for your help. Note: The request for comments statements about the gross-ness of the scan_mutex still stand. Signed-off-by: Michael Reed Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index f2db7a41cf1..c76e73a3ffb 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1284,7 +1284,9 @@ EXPORT_SYMBOL(fc_release_transport); * @work: Work to queue for execution. * * Return value: - * 0 on success / != 0 for error + * 1 - work queued for execution + * 0 - work is already queued + * -EINVAL - work queue doesn't exist **/ static int fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) @@ -1434,8 +1436,6 @@ fc_starget_delete(void *data) struct Scsi_Host *shost = rport_to_shost(rport); unsigned long flags; - scsi_target_unblock(&rport->dev); - spin_lock_irqsave(shost->host_lock, flags); if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { spin_unlock_irqrestore(shost->host_lock, flags); @@ -1707,6 +1707,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + return rport; } } @@ -1762,9 +1764,10 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, /* initiate a scan of the target */ rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); - } - - spin_unlock_irqrestore(shost->host_lock, flags); + spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + } else + spin_unlock_irqrestore(shost->host_lock, flags); return rport; } @@ -1938,6 +1941,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) rport->flags |= FC_RPORT_SCAN_PENDING; scsi_queue_work(shost, &rport->scan_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); } } EXPORT_SYMBOL(fc_remote_port_rolechg); @@ -1970,8 +1974,9 @@ fc_timeout_deleted_rport(void *data) dev_printk(KERN_ERR, &rport->dev, "blocked FC remote port time out: no longer" " a FCP target, removing starget\n"); - fc_queue_work(shost, &rport->stgt_delete_work); spin_unlock_irqrestore(shost->host_lock, flags); + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); return; } @@ -2035,17 +2040,15 @@ fc_timeout_deleted_rport(void *data) * went away and didn't come back - we'll remove * all attached scsi devices. */ - fc_queue_work(shost, &rport->stgt_delete_work); - spin_unlock_irqrestore(shost->host_lock, flags); + + scsi_target_unblock(&rport->dev); + fc_queue_work(shost, &rport->stgt_delete_work); } /** * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. * - * Will unblock the target (in case it went away and has now come back), - * then invoke a scan. - * * @data: remote port to be scanned. **/ static void @@ -2057,7 +2060,6 @@ fc_scsi_scan_rport(void *data) if ((rport->port_state == FC_PORTSTATE_ONLINE) && (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { - scsi_target_unblock(&rport->dev); scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id, SCAN_WILD_CARD, 1); } -- cgit v1.2.3 From 1c9e16e47a22c61d99aabb1c154e5106ddbf3575 Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 16 May 2006 16:13:36 -0400 Subject: [SCSI] update max sdev block limit Updated patch to address comments from Pat Mansfield and Michael Reed: Bumped max to 600 (10mins). Set default dev_loss_tmo to a value other than the max (30s). Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_priv.h | 2 +- drivers/scsi/scsi_transport_fc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index a1727a0e1bd..117c2336f33 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -117,7 +117,7 @@ extern struct bus_type scsi_bus_type; * classes. */ -#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT (HZ*60) +#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */ extern int scsi_internal_device_block(struct scsi_device *sdev); extern int scsi_internal_device_unblock(struct scsi_device *sdev); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index c76e73a3ffb..df6263dfd79 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -368,7 +368,7 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class, * should insulate the loss of a remote port. * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. */ -static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT; +static unsigned int fc_dev_loss_tmo = 60; /* seconds */ module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dev_loss_tmo, -- cgit v1.2.3 From 3bdad7bd253f17ead00b4af2e82f84e9522c95ac Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 26 Jun 2006 14:19:59 -0400 Subject: [SCSI] fc transport: bug fix: correct references Original post was incorrect as it didn't realize that we already had a self-referenc due to device_initialize(), and we were really only missing the put on our own reference. This was hidden by the other bug which had the midlayer reusing stargets after they were already free, which was doing too many puts on our rport. Updating FC transport for: - Add put in fc_rport_final_delete(), to release the rport. Prior, we were leaving the rport with a reference, thus the shost with references, etc. If the driver was unloaded, shosts and rports remained, along with work threads, etc - Fix fc_rport_create failure path - too many put's on parent - Add commenting to easily track ref taking. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index df6263dfd79..b03aa85108e 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -1476,7 +1476,8 @@ fc_rport_final_delete(void *data) transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ + put_device(dev); /* for self-reference */ } @@ -1537,13 +1538,13 @@ fc_rport_create(struct Scsi_Host *shost, int channel, else rport->scsi_target_id = -1; list_add_tail(&rport->peers, &fc_host->rports); - get_device(&shost->shost_gendev); + get_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); dev = &rport->dev; - device_initialize(dev); - dev->parent = get_device(&shost->shost_gendev); + device_initialize(dev); /* takes self reference */ + dev->parent = get_device(&shost->shost_gendev); /* parent reference */ dev->release = fc_rport_dev_release; sprintf(dev->bus_id, "rport-%d:%d-%d", shost->host_no, channel, rport->number); @@ -1567,10 +1568,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel, delete_rport: transport_destroy_device(dev); - put_device(dev->parent); spin_lock_irqsave(shost->host_lock, flags); list_del(&rport->peers); - put_device(&shost->shost_gendev); + put_device(&shost->shost_gendev); /* for fc_host->rport list */ spin_unlock_irqrestore(shost->host_lock, flags); put_device(dev->parent); kfree(rport); -- cgit v1.2.3 From a144c5ae0956fb262e6c82624c82b1110a451437 Mon Sep 17 00:00:00 2001 From: Brian King Date: Tue, 27 Jun 2006 11:10:31 -0500 Subject: [SCSI] scsi: Add allow_restart sysfs class attribute This is a resend of a patch I generated in response to an email sent by Ruben Faelens . His original email to linux-scsi requested a method in which he could spin down a scsi disk when not in use and have the kernel automatically spin it back up when an I/O was generated to the disk. The infrastructure to automatically spin a disk up has been in the scsi error handler for some time now, but it is not enabled by default. This patch adds an sd sysfs attribute which allows userspace to enable this behavior. Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index f899ff0cf00..2e96c3d8f7e 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -208,6 +208,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, return count; } +static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf, + size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (sdp->type != TYPE_DISK) + return -EINVAL; + + sdp->allow_restart = simple_strtoul(buf, NULL, 10); + + return count; +} + static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(cdev); @@ -223,10 +240,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf) return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); } +static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + + return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); +} + static struct class_device_attribute sd_disk_attrs[] = { __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), + __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, + sd_store_allow_restart), __ATTR_NULL, }; -- cgit v1.2.3 From 309bd271211caa5a04a8137649cebd7691376351 Mon Sep 17 00:00:00 2001 From: Brian King Date: Tue, 27 Jun 2006 11:10:43 -0500 Subject: [SCSI] scsi: Device scanning oops for offlined devices (resend) If a device gets offlined as a result of the Inquiry sent during scanning, the following oops can occur. After the disk gets put into the SDEV_OFFLINE state, the error handler sends back the failed inquiry, which wakes the thread doing the scan. This starts a race between the scanning thread freeing the scsi device and the error handler calling scsi_run_host_queues to restart the host. Since the disk is in the SDEV_OFFLINE state, scsi_device_get will still work, which results in __scsi_iterate_devices getting a reference to the scsi disk when it shouldn't. The following execution thread causes the oops: CPU 0 (scan) CPU 1 (eh) --------------------------------------------------------- scsi_probe_and_add_lun .... scsi_eh_offline_sdevs scsi_eh_flush_done_q scsi_destroy_sdev scsi_device_dev_release scsi_restart_operations scsi_run_host_queues __scsi_iterate_devices get_device scsi_device_dev_release_usercontext scsi_run_queue <---OOPS---> The patch fixes this by changing the state of the sdev to SDEV_DEL before doing the final put_device, which should prevent the race from occurring. Original oops follows: Badness in kref_get at lib/kref.c:32 Call Trace: [C00000002F4476D0] [C00000000000EE20] .show_stack+0x68/0x1b0 (unreliable) [C00000002F447770] [C00000000037515C] .program_check_exception+0x1cc/0x5a8 [C00000002F447840] [C00000000000446C] program_check_common+0xec/0x100 Exception: 700 at .kref_get+0x10/0x28 LR = .kobject_get+0x20/0x3c [C00000002F447B30] [C00000002F447BC0] 0xc00000002f447bc0 (unreliable) [C00000002F447BB0] [C000000000254BDC] .get_device+0x20/0x3c [C00000002F447C30] [D000000000063188] .scsi_device_get+0x34/0xdc [scsi_mod] [C00000002F447CC0] [D0000000000633EC] .__scsi_iterate_devices+0x50/0xbc [scsi_mod] [C00000002F447D60] [D00000000006A910] .scsi_run_host_queues+0x34/0x5c [scsi_mod] [C00000002F447DF0] [D000000000069054] .scsi_error_handler+0xdb4/0xe44 [scsi_mod] [C00000002F447EE0] [C00000000007B4E0] .kthread+0x128/0x178 [C00000002F447F90] [C000000000025E84] .kernel_thread+0x4c/0x68 Unable to handle kernel paging request for <7>PCI: Enabling device: (0002:41:01.1), cmd 143 data at address 0x000001b8 Faulting instruction address: 0xd0000000000698e4 sym1: <1010-66> rev 0x1 at pci 0002:41:01.1 irq 216 sym1: No NVRAM, ID 7, Fast-80, LVD, parity checking sym1: SCSI BUS has been reset. scsi2 : sym-2.2.2 cpu 0x0: Vector: 300 (Data Access) at [c00000002f447a30] pc: d0000000000698e4: .scsi_run_queue+0x2c/0x218 [scsi_mod] lr: d00000000006a904: .scsi_run_host_queues+0x28/0x5c [scsi_mod] sp: c00000002f447cb0 msr: 9000000000009032 dar: 1b8 dsisr: 40000000 current = 0xc0000000045fecd0 paca = 0xc00000000048ee80 pid = 1123, comm = scsi_eh_1 enter ? for help [c00000002f447d60] d00000000006a904 .scsi_run_host_queues+0x28/0x5c [scsi_mod] [c00000002f447df0] d000000000069054 .scsi_error_handler+0xdb4/0xe44 [scsi_mod] [c00000002f447ee0] c00000000007b4e0 .kthread+0x128/0x178 [c00000002f447f90] c000000000025e84 .kernel_thread+0x4c/0x68 Signed-off-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 3 +++ drivers/scsi/scsi_scan.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 68e0d7dbe6c..bf5191f6aaa 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2037,6 +2037,9 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) case SDEV_DEL: switch (oldstate) { + case SDEV_CREATED: + case SDEV_RUNNING: + case SDEV_OFFLINE: case SDEV_CANCEL: break; default: diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 0f7e6f94d66..4c31799e271 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -810,6 +810,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) static inline void scsi_destroy_sdev(struct scsi_device *sdev) { + scsi_device_set_state(sdev, SDEV_DEL); if (sdev->host->hostt->slave_destroy) sdev->host->hostt->slave_destroy(sdev); transport_destroy_device(&sdev->sdev_gendev); -- cgit v1.2.3 From 2076eb6ab8339bf09620a0160be3607bbbb61a50 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 27 Jun 2006 14:39:06 -0600 Subject: [SCSI] fusion : mpi header update MPI Header Update Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/lsi/fc_log.h | 89 ---------------- drivers/message/fusion/lsi/mpi.h | 5 +- drivers/message/fusion/lsi/mpi_cnfg.h | 158 +++++++++++++++++++++++++---- drivers/message/fusion/lsi/mpi_history.txt | 76 +++++++++----- drivers/message/fusion/lsi/mpi_init.h | 4 +- drivers/message/fusion/lsi/mpi_ioc.h | 154 ++++++++++++++++++++++------ drivers/message/fusion/lsi/mpi_log_sas.h | 82 ++++++++++++++- drivers/message/fusion/lsi/mpi_sas.h | 13 ++- drivers/message/fusion/lsi/mpi_targ.h | 5 +- 9 files changed, 413 insertions(+), 173 deletions(-) delete mode 100644 drivers/message/fusion/lsi/fc_log.h diff --git a/drivers/message/fusion/lsi/fc_log.h b/drivers/message/fusion/lsi/fc_log.h deleted file mode 100644 index dc98d46f907..00000000000 --- a/drivers/message/fusion/lsi/fc_log.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved. - * - * NAME: fc_log.h - * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips - * DESCRIPTION: Contains the enumerated list of values that may be returned - * in the IOCLogInfo field of a MPI Default Reply Message. - * - * CREATION DATE: 6/02/2000 - * ID: $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $ - */ - - -/* - * MpiIocLogInfo_t enum - * - * These 32 bit values are used in the IOCLogInfo field of the MPI reply - * messages. - * The value is 0xabcccccc where - * a = The type of log info as per the MPI spec. Since these codes are - * all for Fibre Channel this value will always be 2. - * b = Specifies a subclass of the firmware where - * 0 = FCP Initiator - * 1 = FCP Target - * 2 = LAN - * 3 = MPI Message Layer - * 4 = FC Link - * 5 = Context Manager - * 6 = Invalid Field Offset - * 7 = State Change Info - * all others are reserved for future use - * c = A specific value within the subclass. - * - * NOTE: Any new values should be added to the end of each subclass so that the - * codes remain consistent across firmware releases. - */ -typedef enum _MpiIocLogInfoFc -{ - MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000, - MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primative */ - MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Bad Rx Frame, overrun */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */ - MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN = 0x20000007, /* Scatter Gather overrun */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS = 0x20000008, /* Receiver detected context mismatch via invalid header */ - MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type */ - MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE = 0x2000000A, /* Link failure occurred */ - MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT = 0x2000000B, /* Transmitter timeout error */ - - MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000, - MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */ - MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */ - MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */ - MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */ - MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */ - MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */ - MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound queue after a logout */ - MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */ - - MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000, - MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */ - MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */ - MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */ - MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */ - - MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000, - - MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000, - MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */ - MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */ - MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */ - MPI_IOCLOGINFO_FC_LINK_CRC_ERROR = 0x24000004, /* CRC check detected error on received frame */ - - MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000, - - MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */ - MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff, - - MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */ - -} MpiIocLogInfoFc_t; diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 02cdc840a06..81ad77622da 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -6,7 +6,7 @@ * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.10 + * mpi.h Version: 01.05.11 * * Version History * --------------- @@ -76,6 +76,7 @@ * Added EEDP IOCStatus codes. * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -106,7 +107,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x0C) +#define MPI_HEADER_VERSION_UNIT (0x0D) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index b1becec27e1..47e13e360c1 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.11 + * mpi_cnfg.h Version: 01.05.12 * * Version History * --------------- @@ -266,6 +266,16 @@ * Added postpone SATA Init bit to SAS IO Unit Page 1 * ControlFlags. * Changed LogEntry format for Log Page 0. + * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4. + * Added Manufacturing Page 7. + * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING. + * Added IOC Page 6. + * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2. + * Added MaxLBAHigh field to RAID Volume Page 0. + * Added Nvdata version fields to SAS IO Unit Page 0. + * Added AdditionalControlFlags, MaxTargetPortConnectTime, + * ReportDeviceMissingDelay, and IODeviceMissingDelay + * fields to SAS IO Unit Page 1. * -------------------------------------------------------------------------- */ @@ -631,9 +641,11 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4 } CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4, ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t; -#define MPI_MANUFACTURING4_PAGEVERSION (0x03) +#define MPI_MANUFACTURING4_PAGEVERSION (0x04) /* defines for the Flags field */ +#define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80) +#define MPI_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x40) #define MPI_MANPAGE4_IME_DISABLE (0x20) #define MPI_MANPAGE4_IM_DISABLE (0x10) #define MPI_MANPAGE4_IS_DISABLE (0x08) @@ -668,6 +680,66 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_6 #define MPI_MANUFACTURING6_PAGEVERSION (0x00) +typedef struct _MPI_MANPAGE7_CONNECTOR_INFO +{ + U32 Pinout; /* 00h */ + U8 Connector[16]; /* 04h */ + U8 Location; /* 14h */ + U8 Reserved1; /* 15h */ + U16 Slot; /* 16h */ + U32 Reserved2; /* 18h */ +} MPI_MANPAGE7_CONNECTOR_INFO, MPI_POINTER PTR_MPI_MANPAGE7_CONNECTOR_INFO, + MpiManPage7ConnectorInfo_t, MPI_POINTER pMpiManPage7ConnectorInfo_t; + +/* defines for the Pinout field */ +#define MPI_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000) +#define MPI_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200) +#define MPI_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100) +#define MPI_MANPAGE7_PINOUT_SFF_8482 (0x00000002) +#define MPI_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001) + +/* defines for the Location field */ +#define MPI_MANPAGE7_LOCATION_UNKNOWN (0x01) +#define MPI_MANPAGE7_LOCATION_INTERNAL (0x02) +#define MPI_MANPAGE7_LOCATION_EXTERNAL (0x04) +#define MPI_MANPAGE7_LOCATION_SWITCHABLE (0x08) +#define MPI_MANPAGE7_LOCATION_AUTO (0x10) +#define MPI_MANPAGE7_LOCATION_NOT_PRESENT (0x20) +#define MPI_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) + +/* + * Host code (drivers, BIOS, utilities, etc.) should leave this define set to + * one and check NumPhys at runtime. + */ +#ifndef MPI_MANPAGE7_CONNECTOR_INFO_MAX +#define MPI_MANPAGE7_CONNECTOR_INFO_MAX (1) +#endif + +typedef struct _CONFIG_PAGE_MANUFACTURING_7 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 Reserved1; /* 04h */ + U32 Reserved2; /* 08h */ + U32 Flags; /* 0Ch */ + U8 EnclosureName[16]; /* 10h */ + U8 NumPhys; /* 20h */ + U8 Reserved3; /* 21h */ + U16 Reserved4; /* 22h */ + MPI_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI_MANPAGE7_CONNECTOR_INFO_MAX]; /* 24h */ +} CONFIG_PAGE_MANUFACTURING_7, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_7, + ManufacturingPage7_t, MPI_POINTER pManufacturingPage7_t; + +#define MPI_MANUFACTURING7_PAGEVERSION (0x00) + +/* defines for the Flags field */ +#define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) + + /**************************************************************************** * IO Unit Config Pages ****************************************************************************/ @@ -867,7 +939,7 @@ typedef struct _CONFIG_PAGE_IOC_2 } CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, IOCPage2_t, MPI_POINTER pIOCPage2_t; -#define MPI_IOCPAGE2_PAGEVERSION (0x03) +#define MPI_IOCPAGE2_PAGEVERSION (0x04) /* IOC Page 2 Capabilities flags */ @@ -878,6 +950,7 @@ typedef struct _CONFIG_PAGE_IOC_2 #define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010) #define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020) #define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING (0x10000000) #define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000) #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000) #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000) @@ -975,6 +1048,44 @@ typedef struct _CONFIG_PAGE_IOC_5 #define MPI_IOCPAGE5_PAGEVERSION (0x00) +typedef struct _CONFIG_PAGE_IOC_6 +{ + CONFIG_PAGE_HEADER Header; /* 00h */ + U32 CapabilitiesFlags; /* 04h */ + U8 MaxDrivesIS; /* 08h */ + U8 MaxDrivesIM; /* 09h */ + U8 MaxDrivesIME; /* 0Ah */ + U8 Reserved1; /* 0Bh */ + U8 MinDrivesIS; /* 0Ch */ + U8 MinDrivesIM; /* 0Dh */ + U8 MinDrivesIME; /* 0Eh */ + U8 Reserved2; /* 0Fh */ + U8 MaxGlobalHotSpares; /* 10h */ + U8 Reserved3; /* 11h */ + U16 Reserved4; /* 12h */ + U32 Reserved5; /* 14h */ + U32 SupportedStripeSizeMapIS; /* 18h */ + U32 SupportedStripeSizeMapIME; /* 1Ch */ + U32 Reserved6; /* 20h */ + U8 MetadataSize; /* 24h */ + U8 Reserved7; /* 25h */ + U16 Reserved8; /* 26h */ + U16 MaxBadBlockTableEntries; /* 28h */ + U16 Reserved9; /* 2Ah */ + U16 IRNvsramUsage; /* 2Ch */ + U16 Reserved10; /* 2Eh */ + U32 IRNvsramVersion; /* 30h */ + U32 Reserved11; /* 34h */ + U32 Reserved12; /* 38h */ +} CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6, + IOCPage6_t, MPI_POINTER pIOCPage6_t; + +#define MPI_IOCPAGE6_PAGEVERSION (0x00) + +/* IOC Page 6 Capabilities Flags */ + +#define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) + /**************************************************************************** * BIOS Config Pages @@ -1218,13 +1329,13 @@ typedef struct _CONFIG_PAGE_BIOS_2 U32 Reserved5; /* 14h */ U32 Reserved6; /* 18h */ U8 BootDeviceForm; /* 1Ch */ - U8 Reserved7; /* 1Dh */ + U8 PrevBootDeviceForm; /* 1Ch */ U16 Reserved8; /* 1Eh */ MPI_BIOSPAGE2_BOOT_DEVICE BootDevice; /* 20h */ } CONFIG_PAGE_BIOS_2, MPI_POINTER PTR_CONFIG_PAGE_BIOS_2, BIOSPage2_t, MPI_POINTER pBIOSPage2_t; -#define MPI_BIOSPAGE2_PAGEVERSION (0x01) +#define MPI_BIOSPAGE2_PAGEVERSION (0x02) #define MPI_BIOSPAGE2_FORM_MASK (0x0F) #define MPI_BIOSPAGE2_FORM_ADAPTER_ORDER (0x00) @@ -2080,7 +2191,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 RAID_VOL0_STATUS VolumeStatus; /* 08h */ RAID_VOL0_SETTINGS VolumeSettings; /* 0Ch */ U32 MaxLBA; /* 10h */ - U32 Reserved1; /* 14h */ + U32 MaxLBAHigh; /* 14h */ U32 StripeSize; /* 18h */ U32 Reserved2; /* 1Ch */ U32 Reserved3; /* 20h */ @@ -2092,7 +2203,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06) /* values for RAID Volume Page 0 InactiveStatus field */ #define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) @@ -2324,7 +2435,8 @@ typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 { CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ - U32 Reserved1; /* 08h */ + U16 NvdataVersionDefault; /* 08h */ + U16 NvdataVersionPersistent; /* 0Ah */ U8 NumPhys; /* 0Ch */ U8 Reserved2; /* 0Dh */ U16 Reserved3; /* 0Eh */ @@ -2332,7 +2444,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 } CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; -#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03) +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x04) /* values for SAS IO Unit Page 0 PortFlags */ #define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) @@ -2373,12 +2485,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA { - U8 Port; /* 00h */ - U8 PortFlags; /* 01h */ - U8 PhyFlags; /* 02h */ - U8 MaxMinLinkRate; /* 03h */ - U32 ControllerPhyDeviceInfo;/* 04h */ - U32 Reserved1; /* 08h */ + U8 Port; /* 00h */ + U8 PortFlags; /* 01h */ + U8 PhyFlags; /* 02h */ + U8 MaxMinLinkRate; /* 03h */ + U32 ControllerPhyDeviceInfo; /* 04h */ + U16 MaxTargetPortConnectTime; /* 08h */ + U16 Reserved1; /* 0Ah */ } MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA, SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData; @@ -2395,15 +2508,17 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ U16 ControlFlags; /* 08h */ U16 MaxNumSATATargets; /* 0Ah */ - U32 Reserved1; /* 0Ch */ + U16 AdditionalControlFlags; /* 0Ch */ + U16 Reserved1; /* 0Eh */ U8 NumPhys; /* 10h */ U8 SATAMaxQDepth; /* 11h */ - U16 Reserved2; /* 12h */ + U8 ReportDeviceMissingDelay; /* 12h */ + U8 IODeviceMissingDelay; /* 13h */ MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 14h */ } CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1, SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t; -#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x05) +#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06) /* values for SAS IO Unit Page 1 ControlFlags */ #define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) @@ -2428,6 +2543,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 #define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) #define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) +/* values for SAS IO Unit Page 1 AdditionalControlFlags */ +#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) + +/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ +#define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) +#define MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16 (0x80) + /* values for SAS IO Unit Page 1 PortFlags */ #define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00) #define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04) diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index 4a5f8dd1d76..582cfe7c2aa 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -6,25 +6,25 @@ Copyright (c) 2000-2005 LSI Logic Corporation. --------------------------------------- - Header Set Release Version: 01.05.12 - Header Set Release Date: 08-30-05 + Header Set Release Version: 01.05.13 + Header Set Release Date: 03-27-06 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.10 01.05.09 - mpi_ioc.h 01.05.10 01.05.09 - mpi_cnfg.h 01.05.11 01.05.10 - mpi_init.h 01.05.06 01.05.06 - mpi_targ.h 01.05.05 01.05.05 + mpi.h 01.05.11 01.05.10 + mpi_ioc.h 01.05.11 01.05.10 + mpi_cnfg.h 01.05.12 01.05.11 + mpi_init.h 01.05.07 01.05.06 + mpi_targ.h 01.05.06 01.05.05 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 mpi_raid.h 01.05.02 01.05.02 mpi_tool.h 01.05.03 01.05.03 mpi_inb.h 01.05.01 01.05.01 - mpi_sas.h 01.05.02 01.05.01 - mpi_type.h 01.05.02 01.05.01 - mpi_history.txt 01.05.12 01.05.11 + mpi_sas.h 01.05.03 01.05.02 + mpi_type.h 01.05.02 01.05.02 + mpi_history.txt 01.05.13 01.05.12 * Date Version Description @@ -93,6 +93,7 @@ mpi.h * Added EEDP IOCStatus codes. * 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT. * 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target. + * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- mpi_ioc.h @@ -170,6 +171,17 @@ mpi_ioc.h * Added new ReasonCode value for SAS Device Status Change * event. * Added new family code for FC949E. + * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR. + * Added additional Reason Codes and more event data fields + * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE. + * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and + * new event. + * Added MPI_EVENT_SAS_SMP_ERROR and event data structure. + * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event + * data structure. + * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event + * data structure. + * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -425,6 +437,16 @@ mpi_cnfg.h * Added postpone SATA Init bit to SAS IO Unit Page 1 * ControlFlags. * Changed LogEntry format for Log Page 0. + * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4. + * Added Manufacturing Page 7. + * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING. + * Added IOC Page 6. + * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2. + * Added MaxLBAHigh field to RAID Volume Page 0. + * Added Nvdata version fields to SAS IO Unit Page 0. + * Added AdditionalControlFlags, MaxTargetPortConnectTime, + * ReportDeviceMissingDelay, and IODeviceMissingDelay + * fields to SAS IO Unit Page 1. * -------------------------------------------------------------------------- mpi_init.h @@ -467,6 +489,7 @@ mpi_init.h * Added four new defines for SEP SlotStatus. * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. + * 03-27-06 01.05.07 Added Task Management type of Clear ACA. * -------------------------------------------------------------------------- mpi_targ.h @@ -511,6 +534,7 @@ mpi_targ.h * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. + * 03-27-06 01.05.06 Added a comment. * -------------------------------------------------------------------------- mpi_fc.h @@ -610,6 +634,10 @@ mpi_sas.h * 08-30-05 01.05.02 Added DeviceInfo bit for SEP. * Added PrimFlags and Primitive field to SAS IO Unit * Control request, and added a new operation code. + * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal, + * and Remove Device operations to SAS IO Unit Control. + * Added DevHandle field to SAS IO Unit Control request and + * reply. * -------------------------------------------------------------------------- mpi_type.h @@ -625,20 +653,20 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.12 01.05.11 01.05.10 01.05.09 ----------- -------- -------- -------- -------- -mpi.h 01.05.10 01.05.09 01.05.08 01.05.07 -mpi_ioc.h 01.05.10 01.05.09 01.05.09 01.05.08 -mpi_cnfg.h 01.05.11 01.05.10 01.05.09 01.05.08 -mpi_init.h 01.05.06 01.05.06 01.05.05 01.05.04 -mpi_targ.h 01.05.05 01.05.05 01.05.05 01.05.04 -mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 -mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 -mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 -mpi_sas.h 01.05.02 01.05.01 01.05.01 01.05.01 -mpi_type.h 01.05.02 01.05.01 01.05.01 01.05.01 +Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09 +---------- -------- -------- -------- -------- -------- +mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07 +mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08 +mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08 +mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04 +mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04 +mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02 +mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01 +mpi_sas.h 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01 +mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01 Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index 68941f459ca..c1c678989a2 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -6,7 +6,7 @@ * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * mpi_init.h Version: 01.05.06 + * mpi_init.h Version: 01.05.07 * * Version History * --------------- @@ -52,6 +52,7 @@ * Added four new defines for SEP SlotStatus. * 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them * unique in the first 32 characters. + * 03-27-06 01.05.07 Added Task Management type of Clear ACA. * -------------------------------------------------------------------------- */ @@ -427,6 +428,7 @@ typedef struct _MSG_SCSI_TASK_MGMT #define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) #define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) #define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) +#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08) /* MsgFlags bits */ #define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00) diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index 2c5f43fa7c7..18ba407fd39 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.10 + * mpi_ioc.h Version: 01.05.11 * * Version History * --------------- @@ -87,6 +87,17 @@ * Added new ReasonCode value for SAS Device Status Change * event. * Added new family code for FC949E. + * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR. + * Added additional Reason Codes and more event data fields + * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE. + * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and + * new event. + * Added MPI_EVENT_SAS_SMP_ERROR and event data structure. + * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event + * data structure. + * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event + * data structure. + * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION. * -------------------------------------------------------------------------- */ @@ -272,6 +283,7 @@ typedef struct _MSG_IOC_FACTS_REPLY #define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) #define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200) #define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400) +#define MPI_IOCFACTS_CAPABILITY_TLR (0x00000800) /***************************************************************************** @@ -448,30 +460,34 @@ typedef struct _MSG_EVENT_ACK_REPLY /* Event */ -#define MPI_EVENT_NONE (0x00000000) -#define MPI_EVENT_LOG_DATA (0x00000001) -#define MPI_EVENT_STATE_CHANGE (0x00000002) -#define MPI_EVENT_UNIT_ATTENTION (0x00000003) -#define MPI_EVENT_IOC_BUS_RESET (0x00000004) -#define MPI_EVENT_EXT_BUS_RESET (0x00000005) -#define MPI_EVENT_RESCAN (0x00000006) -#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) -#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) -#define MPI_EVENT_LOGOUT (0x00000009) -#define MPI_EVENT_EVENT_CHANGE (0x0000000A) -#define MPI_EVENT_INTEGRATED_RAID (0x0000000B) -#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) -#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) -#define MPI_EVENT_QUEUE_FULL (0x0000000E) -#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) -#define MPI_EVENT_SAS_SES (0x00000010) -#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) -#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012) -#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013) -#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014) -#define MPI_EVENT_IR2 (0x00000015) -#define MPI_EVENT_SAS_DISCOVERY (0x00000016) -#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) +#define MPI_EVENT_NONE (0x00000000) +#define MPI_EVENT_LOG_DATA (0x00000001) +#define MPI_EVENT_STATE_CHANGE (0x00000002) +#define MPI_EVENT_UNIT_ATTENTION (0x00000003) +#define MPI_EVENT_IOC_BUS_RESET (0x00000004) +#define MPI_EVENT_EXT_BUS_RESET (0x00000005) +#define MPI_EVENT_RESCAN (0x00000006) +#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007) +#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008) +#define MPI_EVENT_LOGOUT (0x00000009) +#define MPI_EVENT_EVENT_CHANGE (0x0000000A) +#define MPI_EVENT_INTEGRATED_RAID (0x0000000B) +#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C) +#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D) +#define MPI_EVENT_QUEUE_FULL (0x0000000E) +#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F) +#define MPI_EVENT_SAS_SES (0x00000010) +#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011) +#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012) +#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013) +#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014) +#define MPI_EVENT_IR2 (0x00000015) +#define MPI_EVENT_SAS_DISCOVERY (0x00000016) +#define MPI_EVENT_SAS_BROADCAST_PRIMITIVE (0x00000017) +#define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018) +#define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019) +#define MPI_EVENT_SAS_SMP_ERROR (0x0000001A) +#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021) /* AckRequired field values */ @@ -558,18 +574,25 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE U8 PhyNum; /* 0Eh */ U8 Reserved1; /* 0Fh */ U64 SASAddress; /* 10h */ + U8 LUN[8]; /* 18h */ + U16 TaskTag; /* 20h */ + U16 Reserved2; /* 22h */ } EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, MpiEventDataSasDeviceStatusChange_t, MPI_POINTER pMpiEventDataSasDeviceStatusChange_t; /* MPI SAS Device Status Change Event data ReasonCode values */ -#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) -#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) -#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) -#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03) +#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04) +#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) +#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06) +#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) +#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) +#define MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) +#define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) +#define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) +#define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) /* SCSI Event data for Queue Full event */ @@ -742,6 +765,27 @@ typedef struct _EVENT_DATA_SAS_SES } EVENT_DATA_SAS_SES, MPI_POINTER PTR_EVENT_DATA_SAS_SES, MpiEventDataSasSes_t, MPI_POINTER pMpiEventDataSasSes_t; +/* SAS Broadcast Primitive Event data */ + +typedef struct _EVENT_DATA_SAS_BROADCAST_PRIMITIVE +{ + U8 PhyNum; /* 00h */ + U8 Port; /* 01h */ + U8 PortWidth; /* 02h */ + U8 Primitive; /* 04h */ +} EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MPI_POINTER PTR_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, + MpiEventDataSasBroadcastPrimitive_t, + MPI_POINTER pMpiEventDataSasBroadcastPrimitive_t; + +#define MPI_EVENT_PRIMITIVE_CHANGE (0x01) +#define MPI_EVENT_PRIMITIVE_EXPANDER (0x03) +#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04) +#define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05) +#define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06) +#define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) +#define MPI_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) + /* SAS Phy Link Status Event data */ typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS @@ -804,6 +848,53 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR #define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800) #define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) +/* SAS SMP Error Event data */ + +typedef struct _EVENT_DATA_SAS_SMP_ERROR +{ + U8 Status; /* 00h */ + U8 Port; /* 01h */ + U8 SMPFunctionResult; /* 02h */ + U8 Reserved1; /* 03h */ + U64 SASAddress; /* 04h */ +} EVENT_DATA_SAS_SMP_ERROR, MPI_POINTER PTR_EVENT_DATA_SAS_SMP_ERROR, + MpiEventDataSasSmpError_t, MPI_POINTER pMpiEventDataSasSmpError_t; + +/* defines for the Status field of the SAS SMP Error event */ +#define MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID (0x00) +#define MPI_EVENT_SAS_SMP_CRC_ERROR (0x01) +#define MPI_EVENT_SAS_SMP_TIMEOUT (0x02) +#define MPI_EVENT_SAS_SMP_NO_DESTINATION (0x03) +#define MPI_EVENT_SAS_SMP_BAD_DESTINATION (0x04) + +/* SAS Initiator Device Status Change Event data */ + +typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE +{ + U8 ReasonCode; /* 00h */ + U8 Port; /* 01h */ + U16 DevHandle; /* 02h */ + U64 SASAddress; /* 04h */ +} EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MPI_POINTER PTR_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, + MpiEventDataSasInitDevStatusChange_t, + MPI_POINTER pMpiEventDataSasInitDevStatusChange_t; + +/* defines for the ReasonCode field of the SAS Initiator Device Status Change event */ +#define MPI_EVENT_SAS_INIT_RC_ADDED (0x01) + +/* SAS Initiator Device Table Overflow Event data */ + +typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW +{ + U8 MaxInit; /* 00h */ + U8 CurrentInit; /* 01h */ + U16 Reserved1; /* 02h */ +} EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, + MpiEventDataSasInitTableOverflow_t, + MPI_POINTER pMpiEventDataSasInitTableOverflow_t; + /***************************************************************************** * @@ -1013,5 +1104,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER #define MPI_EXT_IMAGE_TYPE_FW (0x01) #define MPI_EXT_IMAGE_TYPE_NVDATA (0x03) #define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04) +#define MPI_EXT_IMAGE_TYPE_INITIALIZATION (0x05) #endif diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h index a9c14ad132c..871ebc08b70 100644 --- a/drivers/message/fusion/lsi/mpi_log_sas.h +++ b/drivers/message/fusion/lsi/mpi_log_sas.h @@ -13,6 +13,8 @@ #ifndef IOPI_IOCLOGINFO_H_INCLUDED #define IOPI_IOCLOGINFO_H_INCLUDED +#define SAS_LOGINFO_NEXUS_LOSS 0x31170000 +#define SAS_LOGINFO_MASK 0xFFFF0000 /****************************************************************************/ /* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */ @@ -51,6 +53,9 @@ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */ #define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */ + +#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */ + #define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000) #define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */ @@ -103,6 +108,7 @@ #define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000) #define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000) #define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000) +#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101) #define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */ @@ -165,11 +171,81 @@ /****************************************************************************/ /* IR LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IR */ /****************************************************************************/ -#define IR_LOGINFO_CODE_UNUSED1 (0x00010000) -#define IR_LOGINFO_CODE_UNUSED2 (0x00020000) +#define IR_LOGINFO_RAID_ACTION_ERROR (0x00010000) +#define IR_LOGINFO_CODE_UNUSED2 (0x00020000) + +/* Amount of information passed down for Create Volume is too large */ +#define IR_LOGINFO_VOLUME_CREATE_INVALID_LENGTH (0x00010001) +/* Creation of duplicate volume attempted (Bus/Target ID checked) */ +#define IR_LOGINFO_VOLUME_CREATE_DUPLICATE (0x00010002) +/* Creation failed due to maximum number of supported volumes exceeded */ +#define IR_LOGINFO_VOLUME_CREATE_NO_SLOTS (0x00010003) +/* Creation failed due to DMA error in trying to read from host */ +#define IR_LOGINFO_VOLUME_CREATE_DMA_ERROR (0x00010004) +/* Creation failed due to invalid volume type passed down */ +#define IR_LOGINFO_VOLUME_CREATE_INVALID_VOLUME_TYPE (0x00010005) +/* Creation failed due to error reading MFG Page 4 */ +#define IR_LOGINFO_VOLUME_MFG_PAGE4_ERROR (0x00010006) +/* Creation failed when trying to create internal structures */ +#define IR_LOGINFO_VOLUME_INTERNAL_CONFIG_STRUCTURE_ERROR (0x00010007) + +/* Activation failed due to trying to activate an already active volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_AN_ACTIVE_VOLUME (0x00010010) +/* Activation failed due to trying to active unsupported volume type */ +#define IR_LOGINFO_VOLUME_ACTIVATING_INVALID_VOLUME_TYPE (0x00010011) +/* Activation failed due to trying to active too many volumes */ +#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_VOLUMES (0x00010012) +/* Activation failed due to Volume ID in use already */ +#define IR_LOGINFO_VOLUME_ACTIVATING_VOLUME_ID_IN_USE (0x00010013) +/* Activation failed call to activateVolume returned failure */ +#define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014) +/* Activation failed trying to import the volume */ +#define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015) + +/* Phys Disk failed, too many phys disks */ +#define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020) +/* Amount of information passed down for Create Pnysdisk is too large */ +#define IR_LOGINFO_PHYSDISK_CREATE_INVALID_LENGTH (0x00010021) +/* Creation failed due to DMA error in trying to read from host */ +#define IR_LOGINFO_PHYSDISK_CREATE_DMA_ERROR (0x00010022) +/* Creation failed due to invalid Bus TargetID passed down */ +#define IR_LOGINFO_PHYSDISK_CREATE_BUS_TID_INVALID (0x00010023) +/* Creation failed due to error in creating RAID Phys Disk Config Page */ +#define IR_LOGINFO_PHYSDISK_CREATE_CONFIG_PAGE_ERROR (0x00010024) + + +/* Compatibility Error : IR Disabled */ +#define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030) +/* Compatibility Error : Inquiry Comand failed */ +#define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031) +/* Compatibility Error : Device not direct access device */ +#define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032) +/* Compatibility Error : Removable device found */ +#define IR_LOGINFO_COMPAT_ERROR_REMOVABLE_FOUND (0x00010033) +/* Compatibility Error : Device SCSI Version not 2 or higher */ +#define IR_LOGINFO_COMPAT_ERROR_NEED_SCSI_2_OR_HIGHER (0x00010034) +/* Compatibility Error : SATA device, 48 BIT LBA not supported */ +#define IR_LOGINFO_COMPAT_ERROR_SATA_48BIT_LBA_NOT_SUPPORTED (0x00010035) +/* Compatibility Error : Device does not have 512 byte block sizes */ +#define IR_LOGINFO_COMPAT_ERROR_DEVICE_NOT_512_BYTE_BLOCK (0x00010036) +/* Compatibility Error : Volume Type check failed */ +#define IR_LOGINFO_COMPAT_ERROR_VOLUME_TYPE_CHECK_FAILED (0x00010037) +/* Compatibility Error : Volume Type is unsupported by FW */ +#define IR_LOGINFO_COMPAT_ERROR_UNSUPPORTED_VOLUME_TYPE (0x00010038) +/* Compatibility Error : Disk drive too small for use in volume */ +#define IR_LOGINFO_COMPAT_ERROR_DISK_TOO_SMALL (0x00010039) +/* Compatibility Error : Phys disk for Create Volume not found */ +#define IR_LOGINFO_COMPAT_ERROR_PHYS_DISK_NOT_FOUND (0x0001003A) +/* Compatibility Error : membership count error, too many or too few disks for volume type */ +#define IR_LOGINFO_COMPAT_ERROR_MEMBERSHIP_COUNT (0x0001003B) +/* Compatibility Error : Disk stripe sizes must be 64KB */ +#define IR_LOGINFO_COMPAT_ERROR_NON_64K_STRIPE_SIZE (0x0001003C) +/* Compatibility Error : IME size limited to < 2TB */ +#define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D) + /****************************************************************************/ -/* Defines for convienence */ +/* Defines for convenience */ /****************************************************************************/ #define IOC_LOGINFO_PREFIX_IOP ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IOP) #define IOC_LOGINFO_PREFIX_PL ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_PL) diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h index 70514867bdd..50b8f0a8f45 100644 --- a/drivers/message/fusion/lsi/mpi_sas.h +++ b/drivers/message/fusion/lsi/mpi_sas.h @@ -6,7 +6,7 @@ * Title: MPI Serial Attached SCSI structures and definitions * Creation Date: August 19, 2004 * - * mpi_sas.h Version: 01.05.02 + * mpi_sas.h Version: 01.05.03 * * Version History * --------------- @@ -17,6 +17,10 @@ * 08-30-05 01.05.02 Added DeviceInfo bit for SEP. * Added PrimFlags and Primitive field to SAS IO Unit * Control request, and added a new operation code. + * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal, + * and Remove Device operations to SAS IO Unit Control. + * Added DevHandle field to SAS IO Unit Control request and + * reply. * -------------------------------------------------------------------------- */ @@ -209,7 +213,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST U8 Reserved1; /* 01h */ U8 ChainOffset; /* 02h */ U8 Function; /* 03h */ - U16 Reserved2; /* 04h */ + U16 DevHandle; /* 04h */ U8 Reserved3; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ @@ -231,6 +235,9 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST #define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) #define MPI_SAS_OP_MAP_CURRENT (0x09) #define MPI_SAS_OP_SEND_PRIMITIVE (0x0A) +#define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) +#define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) +#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D) /* values for the PrimFlags field */ #define MPI_SAS_PRIMFLAGS_SINGLE (0x08) @@ -245,7 +252,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY U8 Reserved1; /* 01h */ U8 MsgLength; /* 02h */ U8 Function; /* 03h */ - U16 Reserved2; /* 04h */ + U16 DevHandle; /* 04h */ U8 Reserved3; /* 06h */ U8 MsgFlags; /* 07h */ U32 MsgContext; /* 08h */ diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h index 3f462859cee..20b66731577 100644 --- a/drivers/message/fusion/lsi/mpi_targ.h +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -6,7 +6,7 @@ * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * mpi_targ.h Version: 01.05.05 + * mpi_targ.h Version: 01.05.06 * * Version History * --------------- @@ -54,6 +54,7 @@ * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. + * 03-27-06 01.05.06 Added a comment. * -------------------------------------------------------------------------- */ @@ -351,7 +352,7 @@ typedef struct _MSG_TARGET_ASSIST_REQUEST #define TARGET_ASSIST_FLAGS_CONFIRMED (0x08) #define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80) - +/* Standard Target Mode Reply message */ typedef struct _MSG_TARGET_ERROR_REPLY { U16 Reserved; /* 00h */ -- cgit v1.2.3 From 65c92b09acf0218b64f1c7ba4fdabeb8b732c876 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 28 Jun 2006 12:22:50 -0400 Subject: [SCSI] scsi_transport_sas: introduce a sas_port entity this patch introduces a port object, separates out ports and phys, with ports becoming the primary objects of the tree. Signed-off-by: James Bottomley --- drivers/scsi/scsi_sas_internal.h | 10 +- drivers/scsi/scsi_transport_sas.c | 371 ++++++++++++++++++++++++++++++++++---- include/scsi/scsi_transport_sas.h | 37 +++- 3 files changed, 372 insertions(+), 46 deletions(-) diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h index d76e6e3d8ca..e1edab45a37 100644 --- a/drivers/scsi/scsi_sas_internal.h +++ b/drivers/scsi/scsi_sas_internal.h @@ -2,7 +2,8 @@ #define _SCSI_SAS_INTERNAL_H #define SAS_HOST_ATTRS 0 -#define SAS_PORT_ATTRS 17 +#define SAS_PHY_ATTRS 17 +#define SAS_PORT_ATTRS 1 #define SAS_RPORT_ATTRS 7 #define SAS_END_DEV_ATTRS 3 #define SAS_EXPANDER_ATTRS 7 @@ -13,12 +14,14 @@ struct sas_internal { struct sas_domain_function_template *dft; struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS]; - struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS]; + struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS]; + struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS]; struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; struct transport_container phy_attr_cont; + struct transport_container port_attr_cont; struct transport_container rphy_attr_cont; struct transport_container end_dev_attr_cont; struct transport_container expander_attr_cont; @@ -28,7 +31,8 @@ struct sas_internal { * needed by scsi_sysfs.c */ struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; - struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1]; + struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1]; + struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1]; struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 1fe6b2d0185..dd075627e60 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -174,11 +174,28 @@ static int sas_host_match(struct attribute_container *cont, static int do_sas_phy_delete(struct device *dev, void *data) { - if (scsi_is_sas_phy(dev)) + int pass = (int)(unsigned long)data; + + if (pass == 0 && scsi_is_sas_port(dev)) + sas_port_delete(dev_to_sas_port(dev)); + else if (pass == 1 && scsi_is_sas_phy(dev)) sas_phy_delete(dev_to_phy(dev)); return 0; } +/** + * sas_remove_children -- tear down a devices SAS data structures + * @dev: device belonging to the sas object + * + * Removes all SAS PHYs and remote PHYs for a given object + */ +void sas_remove_children(struct device *dev) +{ + device_for_each_child(dev, (void *)0, do_sas_phy_delete); + device_for_each_child(dev, (void *)1, do_sas_phy_delete); +} +EXPORT_SYMBOL(sas_remove_children); + /** * sas_remove_host -- tear down a Scsi_Host's SAS data structures * @shost: Scsi Host that is torn down @@ -188,13 +205,13 @@ static int do_sas_phy_delete(struct device *dev, void *data) */ void sas_remove_host(struct Scsi_Host *shost) { - device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete); + sas_remove_children(&shost->shost_gendev); } EXPORT_SYMBOL(sas_remove_host); /* - * SAS Port attributes + * SAS Phy attributes */ #define sas_phy_show_simple(field, name, format_string, cast) \ @@ -310,7 +327,7 @@ sas_phy_protocol_attr(identify.target_port_protocols, sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", unsigned long long); sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); -sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); +//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8); sas_phy_linkspeed_attr(negotiated_linkrate); sas_phy_linkspeed_attr(minimum_linkrate_hw); sas_phy_linkspeed_attr(minimum_linkrate); @@ -378,9 +395,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) device_initialize(&phy->dev); phy->dev.parent = get_device(parent); phy->dev.release = sas_phy_release; + INIT_LIST_HEAD(&phy->port_siblings); if (scsi_is_sas_expander_device(parent)) { struct sas_rphy *rphy = dev_to_rphy(parent); - sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no, + sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, rphy->scsi_target_id, number); } else sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); @@ -440,8 +458,8 @@ sas_phy_delete(struct sas_phy *phy) { struct device *dev = &phy->dev; - if (phy->rphy) - sas_rphy_delete(phy->rphy); + /* this happens if the phy is still part of a port when deleted */ + BUG_ON(!list_empty(&phy->port_siblings)); transport_remove_device(dev); device_del(dev); @@ -463,6 +481,258 @@ int scsi_is_sas_phy(const struct device *dev) } EXPORT_SYMBOL(scsi_is_sas_phy); +/* + * SAS Port attributes + */ +#define sas_port_show_simple(field, name, format_string, cast) \ +static ssize_t \ +show_sas_port_##name(struct class_device *cdev, char *buf) \ +{ \ + struct sas_port *port = transport_class_to_sas_port(cdev); \ + \ + return snprintf(buf, 20, format_string, cast port->field); \ +} + +#define sas_port_simple_attr(field, name, format_string, type) \ + sas_port_show_simple(field, name, format_string, (type)) \ +static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) + +sas_port_simple_attr(num_phys, num_phys, "%d\n", int); + +static DECLARE_TRANSPORT_CLASS(sas_port_class, + "sas_port", NULL, NULL, NULL); + +static int sas_port_match(struct attribute_container *cont, struct device *dev) +{ + struct Scsi_Host *shost; + struct sas_internal *i; + + if (!scsi_is_sas_port(dev)) + return 0; + shost = dev_to_shost(dev->parent); + + if (!shost->transportt) + return 0; + if (shost->transportt->host_attrs.ac.class != + &sas_host_class.class) + return 0; + + i = to_sas_internal(shost->transportt); + return &i->port_attr_cont.ac == cont; +} + + +static void sas_port_release(struct device *dev) +{ + struct sas_port *port = dev_to_sas_port(dev); + + BUG_ON(!list_empty(&port->phy_list)); + + put_device(dev->parent); + kfree(port); +} + +static void sas_port_create_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id); + sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); +} + +static void sas_port_delete_link(struct sas_port *port, + struct sas_phy *phy) +{ + sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); + sysfs_remove_link(&phy->dev.kobj, "port"); +} + +/** sas_port_alloc - allocate and initialize a SAS port structure + * + * @parent: parent device + * @port_id: port number + * + * Allocates a SAS port structure. It will be added to the device tree + * below the device specified by @parent which must be either a Scsi_Host + * or a sas_expander_device. + * + * Returns %NULL on error + */ +struct sas_port *sas_port_alloc(struct device *parent, int port_id) +{ + struct Scsi_Host *shost = dev_to_shost(parent); + struct sas_port *port; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return NULL; + + port->port_identifier = port_id; + + device_initialize(&port->dev); + + port->dev.parent = get_device(parent); + port->dev.release = sas_port_release; + + mutex_init(&port->phy_list_mutex); + INIT_LIST_HEAD(&port->phy_list); + + if (scsi_is_sas_expander_device(parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent); + sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, + rphy->scsi_target_id, port->port_identifier); + } else + sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, + port->port_identifier); + + transport_setup_device(&port->dev); + + return port; +} +EXPORT_SYMBOL(sas_port_alloc); + +/** + * sas_port_add - add a SAS port to the device hierarchy + * + * @port: port to be added + * + * publishes a port to the rest of the system + */ +int sas_port_add(struct sas_port *port) +{ + int error; + + /* No phys should be added until this is made visible */ + BUG_ON(!list_empty(&port->phy_list)); + + error = device_add(&port->dev); + + if (error) + return error; + + transport_add_device(&port->dev); + transport_configure_device(&port->dev); + + return 0; +} +EXPORT_SYMBOL(sas_port_add); + +/** + * sas_port_free -- free a SAS PORT + * @port: SAS PORT to free + * + * Frees the specified SAS PORT. + * + * Note: + * This function must only be called on a PORT that has not + * sucessfully been added using sas_port_add(). + */ +void sas_port_free(struct sas_port *port) +{ + transport_destroy_device(&port->dev); + put_device(&port->dev); +} +EXPORT_SYMBOL(sas_port_free); + +/** + * sas_port_delete -- remove SAS PORT + * @port: SAS PORT to remove + * + * Removes the specified SAS PORT. If the SAS PORT has an + * associated phys, unlink them from the port as well. + */ +void sas_port_delete(struct sas_port *port) +{ + struct device *dev = &port->dev; + struct sas_phy *phy, *tmp_phy; + + if (port->rphy) { + sas_rphy_delete(port->rphy); + port->rphy = NULL; + } + + mutex_lock(&port->phy_list_mutex); + list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, + port_siblings) { + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + } + mutex_unlock(&port->phy_list_mutex); + + transport_remove_device(dev); + device_del(dev); + transport_destroy_device(dev); + put_device(dev); +} +EXPORT_SYMBOL(sas_port_delete); + +/** + * scsi_is_sas_port -- check if a struct device represents a SAS port + * @dev: device to check + * + * Returns: + * %1 if the device represents a SAS Port, %0 else + */ +int scsi_is_sas_port(const struct device *dev) +{ + return dev->release == sas_port_release; +} +EXPORT_SYMBOL(scsi_is_sas_port); + +/** + * sas_port_add_phy - add another phy to a port to form a wide port + * @port: port to add the phy to + * @phy: phy to add + * + * When a port is initially created, it is empty (has no phys). All + * ports must have at least one phy to operated, and all wide ports + * must have at least two. The current code makes no difference + * between ports and wide ports, but the only object that can be + * connected to a remote device is a port, so ports must be formed on + * all devices with phys if they're connected to anything. + */ +void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + if (unlikely(!list_empty(&phy->port_siblings))) { + /* make sure we're already on this port */ + struct sas_phy *tmp; + + list_for_each_entry(tmp, &port->phy_list, port_siblings) + if (tmp == phy) + break; + /* If this trips, you added a phy that was already + * part of a different port */ + if (unlikely(tmp != phy)) { + dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id); + BUG(); + } + } else { + sas_port_create_link(port, phy); + list_add_tail(&phy->port_siblings, &port->phy_list); + port->num_phys++; + } + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_add_phy); + +/** + * sas_port_delete_phy - remove a phy from a port or wide port + * @port: port to remove the phy from + * @phy: phy to remove + * + * This operation is used for tearing down ports again. It must be + * done to every port or wide port before calling sas_port_delete. + */ +void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) +{ + mutex_lock(&port->phy_list_mutex); + sas_port_delete_link(port, phy); + list_del_init(&phy->port_siblings); + port->num_phys--; + mutex_unlock(&port->phy_list_mutex); +} +EXPORT_SYMBOL(sas_port_delete_phy); + /* * SAS remote PHY attributes. */ @@ -767,7 +1037,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy) * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) +struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); struct sas_end_device *rdev; @@ -780,8 +1050,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent) device_initialize(&rdev->rphy.dev); rdev->rphy.dev.parent = get_device(&parent->dev); rdev->rphy.dev.release = sas_end_device_release; - sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d", - shost->host_no, parent->port_identifier, parent->number); + if (scsi_is_sas_expander_device(parent->dev.parent)) { + struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", + shost->host_no, rphy->scsi_target_id, parent->port_identifier); + } else + sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", + shost->host_no, parent->port_identifier); rdev->rphy.identify.device_type = SAS_END_DEVICE; sas_rphy_initialize(&rdev->rphy); transport_setup_device(&rdev->rphy.dev); @@ -798,7 +1073,7 @@ EXPORT_SYMBOL(sas_end_device_alloc); * Returns: * SAS PHY allocated or %NULL if the allocation failed. */ -struct sas_rphy *sas_expander_alloc(struct sas_phy *parent, +struct sas_rphy *sas_expander_alloc(struct sas_port *parent, enum sas_device_type type) { struct Scsi_Host *shost = dev_to_shost(&parent->dev); @@ -837,7 +1112,7 @@ EXPORT_SYMBOL(sas_expander_alloc); */ int sas_rphy_add(struct sas_rphy *rphy) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); + struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); struct sas_identify *identify = &rphy->identify; @@ -910,7 +1185,7 @@ void sas_rphy_delete(struct sas_rphy *rphy) { struct device *dev = &rphy->dev; - struct sas_phy *parent = dev_to_phy(dev->parent); + struct sas_port *parent = dev_to_sas_port(dev->parent); struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); @@ -920,7 +1195,7 @@ sas_rphy_delete(struct sas_rphy *rphy) break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: - device_for_each_child(dev, NULL, do_sas_phy_delete); + sas_remove_children(dev); break; default: break; @@ -967,7 +1242,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&sas_host->lock); list_for_each_entry(rphy, &sas_host->rphy_list, list) { - struct sas_phy *parent = dev_to_phy(rphy->dev.parent); + struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); if (rphy->identify.device_type != SAS_END_DEVICE || rphy->scsi_target_id == -1) @@ -1003,16 +1278,19 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, #define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE(field) \ +#define SETUP_PHY_ATTRIBUTE(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \ +#define SETUP_PORT_ATTRIBUTE(field) \ + SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) + +#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) -#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \ +#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1) -#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \ +#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func) #define SETUP_END_DEV_ATTRIBUTE(field) \ @@ -1048,6 +1326,11 @@ sas_attach_transport(struct sas_function_template *ft) i->phy_attr_cont.ac.match = sas_phy_match; transport_container_register(&i->phy_attr_cont); + i->port_attr_cont.ac.class = &sas_port_class.class; + i->port_attr_cont.ac.attrs = &i->port_attrs[0]; + i->port_attr_cont.ac.match = sas_port_match; + transport_container_register(&i->port_attr_cont); + i->rphy_attr_cont.ac.class = &sas_rphy_class.class; i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; i->rphy_attr_cont.ac.match = sas_rphy_match; @@ -1066,29 +1349,34 @@ sas_attach_transport(struct sas_function_template *ft) i->f = ft; count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); i->host_attrs[count] = NULL; count = 0; - SETUP_PORT_ATTRIBUTE(initiator_port_protocols); - SETUP_PORT_ATTRIBUTE(target_port_protocols); - SETUP_PORT_ATTRIBUTE(device_type); - SETUP_PORT_ATTRIBUTE(sas_address); - SETUP_PORT_ATTRIBUTE(phy_identifier); - SETUP_PORT_ATTRIBUTE(port_identifier); - SETUP_PORT_ATTRIBUTE(negotiated_linkrate); - SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(minimum_linkrate); - SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw); - SETUP_PORT_ATTRIBUTE(maximum_linkrate); - - SETUP_PORT_ATTRIBUTE(invalid_dword_count); - SETUP_PORT_ATTRIBUTE(running_disparity_error_count); - SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count); - SETUP_PORT_ATTRIBUTE(phy_reset_problem_count); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset); - SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset); + SETUP_PHY_ATTRIBUTE(initiator_port_protocols); + SETUP_PHY_ATTRIBUTE(target_port_protocols); + SETUP_PHY_ATTRIBUTE(device_type); + SETUP_PHY_ATTRIBUTE(sas_address); + SETUP_PHY_ATTRIBUTE(phy_identifier); + //SETUP_PHY_ATTRIBUTE(port_identifier); + SETUP_PHY_ATTRIBUTE(negotiated_linkrate); + SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(minimum_linkrate); + SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); + SETUP_PHY_ATTRIBUTE(maximum_linkrate); + + SETUP_PHY_ATTRIBUTE(invalid_dword_count); + SETUP_PHY_ATTRIBUTE(running_disparity_error_count); + SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); + SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); + SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); i->phy_attrs[count] = NULL; + count = 0; + SETUP_PORT_ATTRIBUTE(num_phys); + i->port_attrs[count] = NULL; + count = 0; SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); @@ -1131,6 +1419,7 @@ void sas_release_transport(struct scsi_transport_template *t) transport_container_unregister(&i->t.host_attrs); transport_container_unregister(&i->phy_attr_cont); + transport_container_unregister(&i->port_attr_cont); transport_container_unregister(&i->rphy_attr_cont); transport_container_unregister(&i->end_dev_attr_cont); transport_container_unregister(&i->expander_attr_cont); @@ -1149,9 +1438,12 @@ static __init int sas_transport_init(void) error = transport_class_register(&sas_phy_class); if (error) goto out_unregister_transport; - error = transport_class_register(&sas_rphy_class); + error = transport_class_register(&sas_port_class); if (error) goto out_unregister_phy; + error = transport_class_register(&sas_rphy_class); + if (error) + goto out_unregister_port; error = transport_class_register(&sas_end_dev_class); if (error) goto out_unregister_rphy; @@ -1165,6 +1457,8 @@ static __init int sas_transport_init(void) transport_class_unregister(&sas_end_dev_class); out_unregister_rphy: transport_class_unregister(&sas_rphy_class); + out_unregister_port: + transport_class_unregister(&sas_port_class); out_unregister_phy: transport_class_unregister(&sas_phy_class); out_unregister_transport: @@ -1178,6 +1472,7 @@ static void __exit sas_transport_exit(void) { transport_class_unregister(&sas_host_class); transport_class_unregister(&sas_phy_class); + transport_class_unregister(&sas_port_class); transport_class_unregister(&sas_rphy_class); transport_class_unregister(&sas_end_dev_class); transport_class_unregister(&sas_expander_class); diff --git a/include/scsi/scsi_transport_sas.h b/include/scsi/scsi_transport_sas.h index 93cfb4bf421..e3c503cd175 100644 --- a/include/scsi/scsi_transport_sas.h +++ b/include/scsi/scsi_transport_sas.h @@ -3,6 +3,7 @@ #include #include +#include struct scsi_transport_template; struct sas_rphy; @@ -55,7 +56,6 @@ struct sas_phy { enum sas_linkrate minimum_linkrate; enum sas_linkrate maximum_linkrate_hw; enum sas_linkrate maximum_linkrate; - u8 port_identifier; /* internal state */ unsigned int local_attached : 1; @@ -66,8 +66,8 @@ struct sas_phy { u32 loss_of_dword_sync_count; u32 phy_reset_problem_count; - /* the other end of the link */ - struct sas_rphy *rphy; + /* for the list of phys belonging to a port */ + struct list_head port_siblings; }; #define dev_to_phy(d) \ @@ -124,6 +124,24 @@ struct sas_expander_device { #define rphy_to_expander_device(r) \ container_of((r), struct sas_expander_device, rphy) +struct sas_port { + struct device dev; + + u8 port_identifier; + int num_phys; + + /* the other end of the link */ + struct sas_rphy *rphy; + + struct mutex phy_list_mutex; + struct list_head phy_list; +}; + +#define dev_to_sas_port(d) \ + container_of((d), struct sas_port, dev) +#define transport_class_to_sas_port(cdev) \ + dev_to_sas_port((cdev)->dev) + /* The functions by which the transport class and the driver communicate */ struct sas_function_template { int (*get_linkerrors)(struct sas_phy *); @@ -133,6 +151,7 @@ struct sas_function_template { }; +void sas_remove_children(struct device *); extern void sas_remove_host(struct Scsi_Host *); extern struct sas_phy *sas_phy_alloc(struct device *, int); @@ -141,13 +160,21 @@ extern int sas_phy_add(struct sas_phy *); extern void sas_phy_delete(struct sas_phy *); extern int scsi_is_sas_phy(const struct device *); -extern struct sas_rphy *sas_end_device_alloc(struct sas_phy *); -extern struct sas_rphy *sas_expander_alloc(struct sas_phy *, enum sas_device_type); +extern struct sas_rphy *sas_end_device_alloc(struct sas_port *); +extern struct sas_rphy *sas_expander_alloc(struct sas_port *, enum sas_device_type); void sas_rphy_free(struct sas_rphy *); extern int sas_rphy_add(struct sas_rphy *); extern void sas_rphy_delete(struct sas_rphy *); extern int scsi_is_sas_rphy(const struct device *); +struct sas_port *sas_port_alloc(struct device *, int); +int sas_port_add(struct sas_port *); +void sas_port_free(struct sas_port *); +void sas_port_delete(struct sas_port *); +void sas_port_add_phy(struct sas_port *, struct sas_phy *); +void sas_port_delete_phy(struct sas_port *, struct sas_phy *); +int scsi_is_sas_port(const struct device *); + extern struct scsi_transport_template * sas_attach_transport(struct sas_function_template *); extern void sas_release_transport(struct scsi_transport_template *); -- cgit v1.2.3 From 547f9a218436ea35baf9a52e981753e44d9cff1f Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 27 Jun 2006 14:42:12 -0600 Subject: [SCSI] mptsas: wide port support * Wide port support added - using James Bottomley's new SAS wide port API. (There is a known problem in sas transport layer reported yesterday to James. The Kobject dev.bus_ids for end devices are not unique across expanders. I have added a work around in this patch, where I asigning an unique port identifier for every port within the host - this solves the problem, but I expect a fix from James in the sas transport). * Adding target_alloc and target_destroy entry points, and moving code over from the slave entry points. * The renaming of some mptscsih_xxx functions declared in mptsas.c, to mptsas_xxx. * Target Reset moved from slave_destroy to hotplug work thread handling (with regard to device removal). Also inhibit IO to end device while device is being broken down . Talked to James Smart about this at Linux Expo (with questions of how the fc transport handles this). * Cleaning up the kzalloc's, and kfree's Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/Makefile | 5 + drivers/message/fusion/mptbase.h | 15 +- drivers/message/fusion/mptsas.c | 963 ++++++++++++++++++++++++++++----------- 3 files changed, 709 insertions(+), 274 deletions(-) diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 51740b34622..b114236f439 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -33,6 +33,11 @@ # For mptfc: #CFLAGS_mptfc.o += -DMPT_DEBUG_FC +# For mptsas: +#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS +#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE + + #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 4720f9ae86a..ddef586e09e 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -76,8 +76,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.03.10" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.10" +#define MPT_LINUX_VERSION_COMMON "3.04.00" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.00" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -342,6 +342,7 @@ typedef struct _VirtTarget { u8 negoFlags; /* bit field, see above */ u8 raidVolume; /* set, if RAID Volume */ u8 type; /* byte 0 of Inquiry data */ + u8 deleted; /* target in process of being removed */ u32 num_luns; u32 luns[8]; /* Max LUNs is 256 */ } VirtTarget; @@ -633,7 +634,7 @@ typedef struct _MPT_ADAPTER int sas_index; /* index refrencing */ MPT_SAS_MGMT sas_mgmt; int num_ports; - struct work_struct mptscsih_persistTask; + struct work_struct sas_persist_task; struct work_struct fc_setup_reset_work; struct list_head fc_rports; @@ -642,6 +643,7 @@ typedef struct _MPT_ADAPTER struct work_struct fc_rescan_work; char fc_rescan_work_q_name[KOBJ_NAME_LEN]; struct workqueue_struct *fc_rescan_work_q; + u8 port_serial_number; } MPT_ADAPTER; /* @@ -893,6 +895,13 @@ typedef struct _mpt_sge { #define DBG_DUMP_REQUEST_FRAME_HDR(mfp) #endif +// debug sas wide ports +#ifdef MPT_DEBUG_SAS_WIDE +#define dsaswideprintk(x) printk x +#else +#define dsaswideprintk(x) +#endif + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index af6ec553ff7..0877023cc79 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -50,11 +50,14 @@ #include #include #include +#include /* for mdelay */ +#include #include #include #include #include +#include #include "mptbase.h" #include "mptscsih.h" @@ -137,23 +140,37 @@ struct mptsas_devinfo { u32 device_info; /* bitfield detailed info about this device */ }; +/* + * Specific details on ports, wide/narrow + */ +struct mptsas_portinfo_details{ + u8 port_id; /* port number provided to transport */ + u16 num_phys; /* number of phys belong to this port */ + u64 phy_bitmask; /* TODO, extend support for 255 phys */ + struct sas_rphy *rphy; /* transport layer rphy object */ + struct sas_port *port; /* transport layer port object */ + struct scsi_target *starget; + struct mptsas_portinfo *port_info; +}; + struct mptsas_phyinfo { u8 phy_id; /* phy index */ - u8 port_id; /* port number this phy is part of */ + u8 port_id; /* firmware port identifier */ u8 negotiated_link_rate; /* nego'd link rate for this phy */ u8 hw_link_rate; /* hardware max/min phys link rate */ u8 programmed_link_rate; /* programmed max/min phy link rate */ + u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/ struct mptsas_devinfo identify; /* point to phy device info */ struct mptsas_devinfo attached; /* point to attached device info */ - struct sas_phy *phy; - struct sas_rphy *rphy; - struct scsi_target *starget; + struct sas_phy *phy; /* transport layer phy object */ + struct mptsas_portinfo *portinfo; + struct mptsas_portinfo_details * port_details; }; struct mptsas_portinfo { struct list_head list; u16 handle; /* unique id to address this */ - u8 num_phys; /* number of phys */ + u16 num_phys; /* number of phys */ struct mptsas_phyinfo *phy_info; }; @@ -169,7 +186,7 @@ struct mptsas_enclosure { u8 sep_channel; /* SEP channel logical channel id */ }; -#ifdef SASDEBUG +#ifdef MPT_DEBUG_SAS static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) { printk("---- IO UNIT PAGE 0 ------------\n"); @@ -305,7 +322,7 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) static inline int mptsas_is_end_device(struct mptsas_devinfo * attached) { - if ((attached->handle) && + if ((attached->sas_address) && (attached->device_info & MPI_SAS_DEVICE_INFO_END_DEVICE) && ((attached->device_info & @@ -319,6 +336,253 @@ mptsas_is_end_device(struct mptsas_devinfo * attached) return 0; } +/* no mutex */ +void +mptsas_port_delete(struct mptsas_portinfo_details * port_details) +{ + struct mptsas_portinfo *port_info; + struct mptsas_phyinfo *phy_info; + u8 i; + + if (!port_details) + return; + + port_info = port_details->port_info; + phy_info = port_info->phy_info; + + dsaswideprintk((KERN_DEBUG "%s: [%p]: port=%02d num_phys=%02d " + "bitmask=0x%016llX\n", + __FUNCTION__, port_details, port_details->port_id, + port_details->num_phys, port_details->phy_bitmask)); + + for (i = 0; i < port_info->num_phys; i++, phy_info++) { + if(phy_info->port_details != port_details) + continue; + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + phy_info->port_details = NULL; + } + kfree(port_details); +} + +static inline struct sas_rphy * +mptsas_get_rphy(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->rphy; + else + return NULL; +} + +static inline void +mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy) +{ + if (phy_info->port_details) { + phy_info->port_details->rphy = rphy; + dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy)); + } + +#ifdef MPT_DEBUG_SAS_WIDE + if (rphy) { + dev_printk(KERN_DEBUG, &rphy->dev, "add:"); + printk("rphy=%p release=%p\n", + rphy, rphy->dev.release); + } +#endif +} + +static inline struct sas_port * +mptsas_get_port(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->port; + else + return NULL; +} + +static inline void +mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port) +{ + if (phy_info->port_details) + phy_info->port_details->port = port; + +#ifdef MPT_DEBUG_SAS_WIDE + if (port) { + dev_printk(KERN_DEBUG, &port->dev, "add: "); + printk("port=%p release=%p\n", + port, port->dev.release); + } +#endif +} + +static inline struct scsi_target * +mptsas_get_starget(struct mptsas_phyinfo *phy_info) +{ + if (phy_info->port_details) + return phy_info->port_details->starget; + else + return NULL; +} + +static inline void +mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target * +starget) +{ + if (phy_info->port_details) + phy_info->port_details->starget = starget; +} + + +/* + * mptsas_setup_wide_ports + * + * Updates for new and existing narrow/wide port configuration + * in the sas_topology + */ +void +mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + struct mptsas_portinfo_details * port_details; + struct mptsas_phyinfo *phy_info, *phy_info_cmp; + u64 sas_address; + int i, j; + + mutex_lock(&ioc->sas_topology_mutex); + + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + if (phy_info->attached.handle) + continue; + port_details = phy_info->port_details; + if (!port_details) + continue; + if (port_details->num_phys < 2) + continue; + /* + * Removing a phy from a port, letting the last + * phy be removed by firmware events. + */ + dsaswideprintk((KERN_DEBUG + "%s: [%p]: port=%d deleting phy = %d\n", + __FUNCTION__, port_details, + port_details->port_id, i)); + port_details->num_phys--; + port_details->phy_bitmask &= ~ (1 << phy_info->phy_id); + memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); + sas_port_delete_phy(port_details->port, phy_info->phy); + phy_info->port_details = NULL; + } + + /* + * Populate and refresh the tree + */ + phy_info = port_info->phy_info; + for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) { + sas_address = phy_info->attached.sas_address; + dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n", + i, sas_address)); + if (!sas_address) + continue; + port_details = phy_info->port_details; + /* + * Forming a port + */ + if (!port_details) { + port_details = kzalloc(sizeof(*port_details), + GFP_KERNEL); + if (!port_details) + goto out; + port_details->num_phys = 1; + port_details->port_info = port_info; + port_details->port_id = ioc->port_serial_number++; + if (phy_info->phy_id < 64 ) + port_details->phy_bitmask |= + (1 << phy_info->phy_id); + phy_info->sas_port_add_phy=1; + dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t" + "phy_id=%d sas_address=0x%018llX\n", + i, sas_address)); + phy_info->port_details = port_details; + } + + if (i == port_info->num_phys - 1) + continue; + phy_info_cmp = &port_info->phy_info[i + 1]; + for (j = i + 1 ; j < port_info->num_phys ; j++, + phy_info_cmp++) { + if (!phy_info_cmp->attached.sas_address) + continue; + if (sas_address != phy_info_cmp->attached.sas_address) + continue; + if (phy_info_cmp->port_details == port_details ) + continue; + dsaswideprintk((KERN_DEBUG + "\t\tphy_id=%d sas_address=0x%018llX\n", + j, phy_info_cmp->attached.sas_address)); + if (phy_info_cmp->port_details) { + port_details->rphy = + mptsas_get_rphy(phy_info_cmp); + port_details->port = + mptsas_get_port(phy_info_cmp); + port_details->starget = + mptsas_get_starget(phy_info_cmp); + port_details->port_id = + phy_info_cmp->port_details->port_id; + port_details->num_phys = + phy_info_cmp->port_details->num_phys; +// port_info->port_serial_number--; + ioc->port_serial_number--; + if (!phy_info_cmp->port_details->num_phys) + kfree(phy_info_cmp->port_details); + } else + phy_info_cmp->sas_port_add_phy=1; + /* + * Adding a phy to a port + */ + phy_info_cmp->port_details = port_details; + if (phy_info_cmp->phy_id < 64 ) + port_details->phy_bitmask |= + (1 << phy_info_cmp->phy_id); + port_details->num_phys++; + } + } + + out: + +#ifdef MPT_DEBUG_SAS_WIDE + for (i = 0; i < port_info->num_phys; i++) { + port_details = port_info->phy_info[i].port_details; + if (!port_details) + continue; + dsaswideprintk((KERN_DEBUG + "%s: [%p]: phy_id=%02d port_id=%02d num_phys=%02d " + "bitmask=0x%016llX\n", + __FUNCTION__, + port_details, i, port_details->port_id, + port_details->num_phys, port_details->phy_bitmask)); + dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n", + port_details->port, port_details->rphy)); + } + dsaswideprintk((KERN_DEBUG"\n")); +#endif + mutex_unlock(&ioc->sas_topology_mutex); +} + +static void +mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget) +{ + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + + if (mptscsih_TMHandler(hd, + MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) { + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + printk(MYIOC_s_WARN_FMT + "Error processing TaskMgmt id=%d TARGET_RESET\n", + ioc->name, vtarget->target_id); + } +} + static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, u32 form, u32 form_specific) @@ -400,11 +664,105 @@ mptsas_slave_configure(struct scsi_device *sdev) return mptscsih_slave_configure(sdev); } -/* - * This is pretty ugly. We will be able to seriously clean it up - * once the DV code in mptscsih goes away and we can properly - * implement ->target_alloc. - */ +static int +mptsas_target_alloc(struct scsi_target *starget) +{ + struct Scsi_Host *host = dev_to_shost(&starget->dev); + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + VirtTarget *vtarget; + u32 target_id; + u32 channel; + struct sas_rphy *rphy; + struct mptsas_portinfo *p; + int i; + + vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL); + if (!vtarget) + return -ENOMEM; + + vtarget->starget = starget; + vtarget->ioc_id = hd->ioc->id; + vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; + + target_id = starget->id; + channel = 0; + + hd->Targets[target_id] = vtarget; + + /* + * RAID volumes placed beyond the last expected port. + */ + if (starget->channel == hd->ioc->num_ports) + goto out; + + rphy = dev_to_rphy(starget->dev.parent); + mutex_lock(&hd->ioc->sas_topology_mutex); + list_for_each_entry(p, &hd->ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + target_id = p->phy_info[i].attached.id; + channel = p->phy_info[i].attached.channel; + mptsas_set_starget(&p->phy_info[i], starget); + + /* + * Exposing hidden raid components + */ + if (mptscsih_is_phys_disk(hd->ioc, target_id)) { + target_id = mptscsih_raid_id_to_num(hd, + target_id); + vtarget->tflags |= + MPT_TARGET_FLAGS_RAID_COMPONENT; + } + mutex_unlock(&hd->ioc->sas_topology_mutex); + goto out; + } + } + mutex_unlock(&hd->ioc->sas_topology_mutex); + + kfree(vtarget); + return -ENXIO; + + out: + vtarget->target_id = target_id; + vtarget->bus_id = channel; + starget->hostdata = vtarget; + return 0; +} + +static void +mptsas_target_destroy(struct scsi_target *starget) +{ + struct Scsi_Host *host = dev_to_shost(&starget->dev); + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + struct sas_rphy *rphy; + struct mptsas_portinfo *p; + int i; + + if (!starget->hostdata) + return; + + if (starget->channel == hd->ioc->num_ports) + goto out; + + rphy = dev_to_rphy(starget->dev.parent); + list_for_each_entry(p, &hd->ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + mptsas_set_starget(&p->phy_info[i], NULL); + goto out; + } + } + + out: + kfree(starget->hostdata); + starget->hostdata = NULL; +} + + static int mptsas_slave_alloc(struct scsi_device *sdev) { @@ -412,61 +770,41 @@ mptsas_slave_alloc(struct scsi_device *sdev) MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; struct sas_rphy *rphy; struct mptsas_portinfo *p; - VirtTarget *vtarget; VirtDevice *vdev; struct scsi_target *starget; - u32 target_id; - int i; + int i; vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); if (!vdev) { - printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", + printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n", hd->ioc->name, sizeof(VirtDevice)); return -ENOMEM; } - sdev->hostdata = vdev; starget = scsi_target(sdev); - vtarget = starget->hostdata; - vtarget->ioc_id = hd->ioc->id; - vdev->vtarget = vtarget; - if (vtarget->num_luns == 0) { - vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; - hd->Targets[sdev->id] = vtarget; - } + vdev->vtarget = starget->hostdata; /* - RAID volumes placed beyond the last expected port. - */ - if (sdev->channel == hd->ioc->num_ports) { - target_id = sdev->id; - vtarget->bus_id = 0; - vdev->lun = 0; + * RAID volumes placed beyond the last expected port. + */ + if (sdev->channel == hd->ioc->num_ports) goto out; - } rphy = dev_to_rphy(sdev->sdev_target->dev.parent); mutex_lock(&hd->ioc->sas_topology_mutex); list_for_each_entry(p, &hd->ioc->sas_topology, list) { for (i = 0; i < p->num_phys; i++) { - if (p->phy_info[i].attached.sas_address == - rphy->identify.sas_address) { - target_id = p->phy_info[i].attached.id; - vtarget->bus_id = p->phy_info[i].attached.channel; - vdev->lun = sdev->lun; - p->phy_info[i].starget = sdev->sdev_target; - /* - * Exposing hidden disk (RAID) - */ - if (mptscsih_is_phys_disk(hd->ioc, target_id)) { - target_id = mptscsih_raid_id_to_num(hd, - target_id); - vdev->vtarget->tflags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - sdev->no_uld_attach = 1; - } - mutex_unlock(&hd->ioc->sas_topology_mutex); - goto out; - } + if (p->phy_info[i].attached.sas_address != + rphy->identify.sas_address) + continue; + vdev->lun = sdev->lun; + /* + * Exposing hidden raid components + */ + if (mptscsih_is_phys_disk(hd->ioc, + p->phy_info[i].attached.id)) + sdev->no_uld_attach = 1; + mutex_unlock(&hd->ioc->sas_topology_mutex); + goto out; } } mutex_unlock(&hd->ioc->sas_topology_mutex); @@ -475,57 +813,39 @@ mptsas_slave_alloc(struct scsi_device *sdev) return -ENXIO; out: - vtarget->target_id = target_id; - vtarget->num_luns++; + vdev->vtarget->num_luns++; + sdev->hostdata = vdev; return 0; } -static void -mptsas_slave_destroy(struct scsi_device *sdev) +static int +mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - struct Scsi_Host *host = sdev->host; - MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; - VirtDevice *vdev; + VirtDevice *vdev = SCpnt->device->hostdata; - /* - * Issue target reset to flush firmware outstanding commands. - */ - vdev = sdev->hostdata; - if (vdev->configured_lun){ - if (mptscsih_TMHandler(hd, - MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - vdev->vtarget->bus_id, - vdev->vtarget->target_id, - 0, 0, 5 /* 5 second timeout */) - < 0){ - - /* The TM request failed! - * Fatal error case. - */ - printk(MYIOC_s_WARN_FMT - "Error processing TaskMgmt id=%d TARGET_RESET\n", - hd->ioc->name, - vdev->vtarget->target_id); - - hd->tmPending = 0; - hd->tmState = TM_STATE_NONE; - } +// scsi_print_command(SCpnt); + if (vdev->vtarget->deleted) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; } - mptscsih_slave_destroy(sdev); + + return mptscsih_qcmd(SCpnt,done); } + static struct scsi_host_template mptsas_driver_template = { .module = THIS_MODULE, .proc_name = "mptsas", .proc_info = mptscsih_proc_info, .name = "MPT SPI Host", .info = mptscsih_info, - .queuecommand = mptscsih_qcmd, - .target_alloc = mptscsih_target_alloc, + .queuecommand = mptsas_qcmd, + .target_alloc = mptsas_target_alloc, .slave_alloc = mptsas_slave_alloc, .slave_configure = mptsas_slave_configure, - .target_destroy = mptscsih_target_destroy, - .slave_destroy = mptsas_slave_destroy, + .target_destroy = mptsas_target_destroy, + .slave_destroy = mptscsih_slave_destroy, .change_queue_depth = mptscsih_change_queue_depth, .eh_abort_handler = mptscsih_abort, .eh_device_reset_handler = mptscsih_dev_reset, @@ -795,7 +1115,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) port_info->num_phys = buffer->NumPhys; port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo),GFP_KERNEL); + sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; @@ -811,6 +1131,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) buffer->PhyData[i].Port; port_info->phy_info[i].negotiated_link_rate = buffer->PhyData[i].NegotiatedLinkRate; + port_info->phy_info[i].portinfo = port_info; } out_free_consistent: @@ -968,7 +1289,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, CONFIGPARMS cfg; SasExpanderPage0_t *buffer; dma_addr_t dma_handle; - int error; + int i, error; hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; hdr.ExtPageLength = 0; @@ -1013,12 +1334,15 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, port_info->num_phys = buffer->NumPhys; port_info->handle = le16_to_cpu(buffer->DevHandle); port_info->phy_info = kcalloc(port_info->num_phys, - sizeof(struct mptsas_phyinfo),GFP_KERNEL); + sizeof(*port_info->phy_info),GFP_KERNEL); if (!port_info->phy_info) { error = -ENOMEM; goto out_free_consistent; } + for (i = 0; i < port_info->num_phys; i++) + port_info->phy_info[i].portinfo = port_info; + out_free_consistent: pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, buffer, dma_handle); @@ -1161,19 +1485,23 @@ static int mptsas_probe_one_phy(struct device *dev, { MPT_ADAPTER *ioc; struct sas_phy *phy; - int error; + struct sas_port *port; + int error = 0; - if (!dev) - return -ENODEV; + if (!dev) { + error = -ENODEV; + goto out; + } if (!phy_info->phy) { phy = sas_phy_alloc(dev, index); - if (!phy) - return -ENOMEM; + if (!phy) { + error = -ENOMEM; + goto out; + } } else phy = phy_info->phy; - phy->port_identifier = phy_info->port_id; mptsas_parse_device_info(&phy->identify, &phy_info->identify); /* @@ -1265,19 +1593,50 @@ static int mptsas_probe_one_phy(struct device *dev, error = sas_phy_add(phy); if (error) { sas_phy_free(phy); - return error; + goto out; } phy_info->phy = phy; } - if ((phy_info->attached.handle) && - (!phy_info->rphy)) { + if (!phy_info->attached.handle || + !phy_info->port_details) + goto out; + + port = mptsas_get_port(phy_info); + ioc = phy_to_ioc(phy_info->phy); + + if (phy_info->sas_port_add_phy) { + + if (!port) { + port = sas_port_alloc(dev, + phy_info->port_details->port_id); + dsaswideprintk((KERN_DEBUG + "sas_port_alloc: port=%p dev=%p port_id=%d\n", + port, dev, phy_info->port_details->port_id)); + if (!port) { + error = -ENOMEM; + goto out; + } + error = sas_port_add(port); + if (error) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + goto out; + } + mptsas_set_port(phy_info, port); + } + dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n", + phy_info->phy_id)); + sas_port_add_phy(port, phy_info->phy); + phy_info->sas_port_add_phy = 0; + } + + if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; struct sas_identify identify; - ioc = phy_to_ioc(phy_info->phy); - /* * Let the hotplug_work thread handle processing * the adding/removing of devices that occur @@ -1285,36 +1644,42 @@ static int mptsas_probe_one_phy(struct device *dev, */ if (ioc->sas_discovery_runtime && mptsas_is_end_device(&phy_info->attached)) - return 0; + goto out; mptsas_parse_device_info(&identify, &phy_info->attached); switch (identify.device_type) { case SAS_END_DEVICE: - rphy = sas_end_device_alloc(phy); + rphy = sas_end_device_alloc(port); break; case SAS_EDGE_EXPANDER_DEVICE: case SAS_FANOUT_EXPANDER_DEVICE: - rphy = sas_expander_alloc(phy, identify.device_type); + rphy = sas_expander_alloc(port, identify.device_type); break; default: rphy = NULL; break; } - if (!rphy) - return 0; /* non-fatal: an rphy can be added later */ + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + goto out; + } rphy->identify = identify; - error = sas_rphy_add(rphy); if (error) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); sas_rphy_free(rphy); - return error; + goto out; } - - phy_info->rphy = rphy; + mptsas_set_rphy(phy_info, rphy); } - return 0; + out: + return error; } static int @@ -1342,8 +1707,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) for (i = 0; i < hba->num_phys; i++) port_info->phy_info[i].negotiated_link_rate = hba->phy_info[i].negotiated_link_rate; - if (hba->phy_info) - kfree(hba->phy_info); + kfree(hba->phy_info); kfree(hba); hba = NULL; } @@ -1362,24 +1726,24 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) port_info->phy_info[i].phy_id; handle = port_info->phy_info[i].identify.handle; - if (port_info->phy_info[i].attached.handle) { + if (port_info->phy_info[i].attached.handle) mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].attached, (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << MPI_SAS_DEVICE_PGAD_FORM_SHIFT), port_info->phy_info[i].attached.handle); - } + } + mptsas_setup_wide_ports(ioc, port_info); + + for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(&ioc->sh->shost_gendev, &port_info->phy_info[i], ioc->sas_index, 1); - ioc->sas_index++; - } return 0; out_free_port_info: - if (hba) - kfree(hba); + kfree(hba); out: return error; } @@ -1388,6 +1752,8 @@ static int mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) { struct mptsas_portinfo *port_info, *p, *ex; + struct device *parent; + struct sas_rphy *rphy; int error = -ENOMEM, i, j; ex = kzalloc(sizeof(*port_info), GFP_KERNEL); @@ -1409,16 +1775,13 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) list_add_tail(&port_info->list, &ioc->sas_topology); } else { port_info->handle = ex->handle; - if (ex->phy_info) - kfree(ex->phy_info); + kfree(ex->phy_info); kfree(ex); ex = NULL; } mutex_unlock(&ioc->sas_topology_mutex); for (i = 0; i < port_info->num_phys; i++) { - struct device *parent; - mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); @@ -1442,34 +1805,34 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) port_info->phy_info[i].attached.phy_id = port_info->phy_info[i].phy_id; } + } - /* - * If we find a parent port handle this expander is - * attached to another expander, else it hangs of the - * HBA phys. - */ - parent = &ioc->sh->shost_gendev; + parent = &ioc->sh->shost_gendev; + for (i = 0; i < port_info->num_phys; i++) { mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(p, &ioc->sas_topology, list) { for (j = 0; j < p->num_phys; j++) { - if (port_info->phy_info[i].identify.handle == + if (port_info->phy_info[i].identify.handle != p->phy_info[j].attached.handle) - parent = &p->phy_info[j].rphy->dev; + continue; + rphy = mptsas_get_rphy(&p->phy_info[j]); + parent = &rphy->dev; } } mutex_unlock(&ioc->sas_topology_mutex); + } + + mptsas_setup_wide_ports(ioc, port_info); + for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++) mptsas_probe_one_phy(parent, &port_info->phy_info[i], ioc->sas_index, 0); - ioc->sas_index++; - } return 0; out_free_port_info: if (ex) { - if (ex->phy_info) - kfree(ex->phy_info); + kfree(ex->phy_info); kfree(ex); } out: @@ -1488,7 +1851,12 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) { struct mptsas_portinfo buffer; struct mptsas_portinfo *port_info, *n, *parent; + struct mptsas_phyinfo *phy_info; + struct scsi_target * starget; + VirtTarget * vtarget; + struct sas_port * port; int i; + u64 expander_sas_address; mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { @@ -1502,6 +1870,25 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { + /* + * Issue target reset to all child end devices + * then mark them deleted to prevent further + * IO going to them. + */ + phy_info = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info++) { + starget = mptsas_get_starget(phy_info); + if (!starget) + continue; + vtarget = starget->hostdata; + if(vtarget->deleted) + continue; + vtarget->deleted = 1; + mptsas_target_reset(ioc, vtarget); + sas_port_delete(mptsas_get_port(phy_info)); + mptsas_port_delete(phy_info->port_details); + } + /* * Obtain the port_info instance to the parent port */ @@ -1511,34 +1898,43 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc) if (!parent) goto next_port; + expander_sas_address = + port_info->phy_info[0].identify.sas_address; + /* * Delete rphys in the parent that point * to this expander. The transport layer will * cleanup all the children. */ - for (i = 0; i < parent->num_phys; i++) { - if ((!parent->phy_info[i].rphy) || - (parent->phy_info[i].attached.sas_address != - port_info->phy_info[i].identify.sas_address)) + phy_info = parent->phy_info; + for (i = 0; i < parent->num_phys; i++, phy_info++) { + port = mptsas_get_port(phy_info); + if (!port) + continue; + if (phy_info->attached.sas_address != + expander_sas_address) continue; - sas_rphy_delete(parent->phy_info[i].rphy); - memset(&parent->phy_info[i].attached, 0, - sizeof(struct mptsas_devinfo)); - parent->phy_info[i].rphy = NULL; - parent->phy_info[i].starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE + dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif + sas_port_delete(port); + mptsas_port_delete(phy_info->port_details); } next_port: + + phy_info = port_info->phy_info; + for (i = 0; i < port_info->num_phys; i++, phy_info++) + mptsas_port_delete(phy_info->port_details); + list_del(&port_info->list); - if (port_info->phy_info) - kfree(port_info->phy_info); + kfree(port_info->phy_info); kfree(port_info); } /* * Free this memory allocated from inside * mptsas_sas_expander_pg0 */ - if (buffer.phy_info) - kfree(buffer.phy_info); + kfree(buffer.phy_info); } mutex_unlock(&ioc->sas_topology_mutex); } @@ -1574,60 +1970,59 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc) /* * Work queue thread to handle Runtime discovery * Mere purpose is the hot add/delete of expanders + *(Mutex UNLOCKED) */ static void -mptscsih_discovery_work(void * arg) +__mptsas_discovery_work(MPT_ADAPTER *ioc) { - struct mptsas_discovery_event *ev = arg; - MPT_ADAPTER *ioc = ev->ioc; u32 handle = 0xFFFF; - mutex_lock(&ioc->sas_discovery_mutex); ioc->sas_discovery_runtime=1; mptsas_delete_expander_phys(ioc); mptsas_probe_hba_phys(ioc); while (!mptsas_probe_expander_phys(ioc, &handle)) ; - kfree(ev); ioc->sas_discovery_runtime=0; +} + +/* + * Work queue thread to handle Runtime discovery + * Mere purpose is the hot add/delete of expanders + *(Mutex LOCKED) + */ +static void +mptsas_discovery_work(void * arg) +{ + struct mptsas_discovery_event *ev = arg; + MPT_ADAPTER *ioc = ev->ioc; + + mutex_lock(&ioc->sas_discovery_mutex); + __mptsas_discovery_work(ioc); mutex_unlock(&ioc->sas_discovery_mutex); + kfree(ev); } static struct mptsas_phyinfo * -mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) +mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address) { struct mptsas_portinfo *port_info; - struct mptsas_devinfo device_info; struct mptsas_phyinfo *phy_info = NULL; - int i, error; - - /* - * Retrieve the parent sas_address - */ - error = mptsas_sas_device_pg0(ioc, &device_info, - (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), - parent_handle); - if (error) - return NULL; + int i; - /* - * The phy_info structures are never deallocated during lifetime of - * a host, so the code below is safe without additional refcounting. - */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { for (i = 0; i < port_info->num_phys; i++) { - if (port_info->phy_info[i].identify.sas_address == - device_info.sas_address && - port_info->phy_info[i].phy_id == phy_id) { - phy_info = &port_info->phy_info[i]; - break; - } + if (port_info->phy_info[i].attached.sas_address + != sas_address) + continue; + if (!mptsas_is_end_device( + &port_info->phy_info[i].attached)) + continue; + phy_info = &port_info->phy_info[i]; + break; } } mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; } @@ -1638,21 +2033,19 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) struct mptsas_phyinfo *phy_info = NULL; int i; - /* - * The phy_info structures are never deallocated during lifetime of - * a host, so the code below is safe without additional refcounting. - */ mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry(port_info, &ioc->sas_topology, list) { - for (i = 0; i < port_info->num_phys; i++) - if (mptsas_is_end_device(&port_info->phy_info[i].attached)) - if (port_info->phy_info[i].attached.id == id) { - phy_info = &port_info->phy_info[i]; - break; - } + for (i = 0; i < port_info->num_phys; i++) { + if (port_info->phy_info[i].attached.id != id) + continue; + if (!mptsas_is_end_device( + &port_info->phy_info[i].attached)) + continue; + phy_info = &port_info->phy_info[i]; + break; + } } mutex_unlock(&ioc->sas_topology_mutex); - return phy_info; } @@ -1660,7 +2053,7 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) * Work queue thread to clear the persitency table */ static void -mptscsih_sas_persist_clear_table(void * arg) +mptsas_persist_clear_table(void * arg) { MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; @@ -1681,7 +2074,6 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) mptsas_reprobe_lun); } - /* * Work queue thread to handle SAS hotplug events */ @@ -1692,14 +2084,17 @@ mptsas_hotplug_work(void *arg) MPT_ADAPTER *ioc = ev->ioc; struct mptsas_phyinfo *phy_info; struct sas_rphy *rphy; + struct sas_port *port; struct scsi_device *sdev; + struct scsi_target * starget; struct sas_identify identify; char *ds = NULL; struct mptsas_devinfo sas_device; VirtTarget *vtarget; + VirtDevice *vdevice; - mutex_lock(&ioc->sas_discovery_mutex); + mutex_lock(&ioc->sas_discovery_mutex); switch (ev->event_type) { case MPTSAS_DEL_DEVICE: @@ -1708,24 +2103,50 @@ mptsas_hotplug_work(void *arg) /* * Sanity checks, for non-existing phys and remote rphys. */ - if (!phy_info) + if (!phy_info || !phy_info->port_details) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; - if (!phy_info->rphy) + } + rphy = mptsas_get_rphy(phy_info); + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; - if (phy_info->starget) { - vtarget = phy_info->starget->hostdata; + } + + starget = mptsas_get_starget(phy_info); + if (starget) { + vtarget = starget->hostdata; - if (!vtarget) + if (!vtarget) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } + /* * Handling RAID components */ if (ev->phys_disk_num_valid) { vtarget->target_id = ev->phys_disk_num; vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - mptsas_reprobe_target(vtarget->starget, 1); + mptsas_reprobe_target(starget, 1); break; } + + vtarget->deleted = 1; + mptsas_target_reset(ioc, vtarget); } if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) @@ -1739,10 +2160,11 @@ mptsas_hotplug_work(void *arg) "removing %s device, channel %d, id %d, phy %d\n", ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); - sas_rphy_delete(phy_info->rphy); - memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); - phy_info->rphy = NULL; - phy_info->starget = NULL; +#ifdef MPT_DEBUG_SAS_WIDE + dev_printk(KERN_DEBUG, &port->dev, "delete\n"); +#endif + sas_port_delete(port); + mptsas_port_delete(phy_info->port_details); break; case MPTSAS_ADD_DEVICE: @@ -1754,59 +2176,60 @@ mptsas_hotplug_work(void *arg) */ if (mptsas_sas_device_pg0(ioc, &sas_device, (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << - MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } - phy_info = mptsas_find_phyinfo_by_parent(ioc, - sas_device.handle_parent, sas_device.phy_id); + ssleep(2); + __mptsas_discovery_work(ioc); - if (!phy_info) { - u32 handle = 0xFFFF; + phy_info = mptsas_find_phyinfo_by_sas_address(ioc, + sas_device.sas_address); - /* - * Its possible when an expander has been hot added - * containing attached devices, the sas firmware - * may send a RC_ADDED event prior to the - * DISCOVERY STOP event. If that occurs, our - * view of the topology in the driver in respect to this - * expander might of not been setup, and we hit this - * condition. - * Therefore, this code kicks off discovery to - * refresh the data. - * Then again, we check whether the parent phy has - * been created. - */ - ioc->sas_discovery_runtime=1; - mptsas_delete_expander_phys(ioc); - mptsas_probe_hba_phys(ioc); - while (!mptsas_probe_expander_phys(ioc, &handle)) - ; - ioc->sas_discovery_runtime=0; - - phy_info = mptsas_find_phyinfo_by_parent(ioc, - sas_device.handle_parent, sas_device.phy_id); - if (!phy_info) - break; + if (!phy_info || !phy_info->port_details) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; } - if (phy_info->starget) { - vtarget = phy_info->starget->hostdata; + starget = mptsas_get_starget(phy_info); + if (starget) { + vtarget = starget->hostdata; - if (!vtarget) + if (!vtarget) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } /* * Handling RAID components */ if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; vtarget->target_id = ev->id; - mptsas_reprobe_target(phy_info->starget, 0); + mptsas_reprobe_target(starget, 0); } break; } - if (phy_info->rphy) + if (mptsas_get_rphy(phy_info)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; + } + port = mptsas_get_port(phy_info); + if (!port) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); + break; + } memcpy(&phy_info->attached, &sas_device, sizeof(struct mptsas_devinfo)); @@ -1823,28 +2246,23 @@ mptsas_hotplug_work(void *arg) ioc->name, ds, ev->channel, ev->id, ev->phy_id); mptsas_parse_device_info(&identify, &phy_info->attached); - switch (identify.device_type) { - case SAS_END_DEVICE: - rphy = sas_end_device_alloc(phy_info->phy); - break; - case SAS_EDGE_EXPANDER_DEVICE: - case SAS_FANOUT_EXPANDER_DEVICE: - rphy = sas_expander_alloc(phy_info->phy, identify.device_type); - break; - default: - rphy = NULL; - break; - } - if (!rphy) + rphy = sas_end_device_alloc(port); + if (!rphy) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); break; /* non-fatal: an rphy can be added later */ + } rphy->identify = identify; if (sas_rphy_add(rphy)) { + dfailprintk((MYIOC_s_ERR_FMT + "%s: exit at line=%d\n", ioc->name, + __FUNCTION__, __LINE__)); sas_rphy_free(rphy); break; } - - phy_info->rphy = rphy; + mptsas_set_rphy(phy_info, rphy); break; case MPTSAS_ADD_RAID: sdev = scsi_device_lookup( @@ -1876,6 +2294,9 @@ mptsas_hotplug_work(void *arg) printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, id %d\n", ioc->name, ioc->num_ports, ev->id); + vdevice = sdev->hostdata; + vdevice->vtarget->deleted = 1; + mptsas_target_reset(ioc, vdevice->vtarget); scsi_remove_device(sdev); scsi_device_put(sdev); mpt_findImVolumes(ioc); @@ -1885,12 +2306,13 @@ mptsas_hotplug_work(void *arg) break; } - kfree(ev); mutex_unlock(&ioc->sas_discovery_mutex); + kfree(ev); + } static void -mptscsih_send_sas_event(MPT_ADAPTER *ioc, +mptsas_send_sas_event(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data) { struct mptsas_hotplug_event *ev; @@ -1906,7 +2328,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, switch (sas_event_data->ReasonCode) { case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); break; @@ -1936,10 +2358,9 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, /* * Persistent table is full. */ - INIT_WORK(&ioc->mptscsih_persistTask, - mptscsih_sas_persist_clear_table, - (void *)ioc); - schedule_work(&ioc->mptscsih_persistTask); + INIT_WORK(&ioc->sas_persist_task, + mptsas_persist_clear_table, (void *)ioc); + schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: /* TODO */ @@ -1951,7 +2372,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, } static void -mptscsih_send_raid_event(MPT_ADAPTER *ioc, +mptsas_send_raid_event(MPT_ADAPTER *ioc, EVENT_DATA_RAID *raid_event_data) { struct mptsas_hotplug_event *ev; @@ -1961,13 +2382,12 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, if (ioc->bus_type != SAS) return; - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { printk(KERN_WARNING "mptsas: lost hotplug event\n"); return; } - memset(ev,0,sizeof(struct mptsas_hotplug_event)); INIT_WORK(&ev->work, mptsas_hotplug_work, ev); ev->ioc = ioc; ev->id = raid_event_data->VolumeID; @@ -2029,7 +2449,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, } static void -mptscsih_send_discovery(MPT_ADAPTER *ioc, +mptsas_send_discovery_event(MPT_ADAPTER *ioc, EVENT_DATA_SAS_DISCOVERY *discovery_data) { struct mptsas_discovery_event *ev; @@ -2044,11 +2464,10 @@ mptscsih_send_discovery(MPT_ADAPTER *ioc, if (discovery_data->DiscoveryStatus) return; - ev = kmalloc(sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) return; - memset(ev,0,sizeof(struct mptsas_discovery_event)); - INIT_WORK(&ev->work, mptscsih_discovery_work, ev); + INIT_WORK(&ev->work, mptsas_discovery_work, ev); ev->ioc = ioc; schedule_work(&ev->work); }; @@ -2076,21 +2495,21 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) switch (event) { case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: - mptscsih_send_sas_event(ioc, + mptsas_send_sas_event(ioc, (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data); break; case MPI_EVENT_INTEGRATED_RAID: - mptscsih_send_raid_event(ioc, + mptsas_send_raid_event(ioc, (EVENT_DATA_RAID *)reply->Data); break; case MPI_EVENT_PERSISTENT_TABLE_FULL: - INIT_WORK(&ioc->mptscsih_persistTask, - mptscsih_sas_persist_clear_table, + INIT_WORK(&ioc->sas_persist_task, + mptsas_persist_clear_table, (void *)ioc); - schedule_work(&ioc->mptscsih_persistTask); + schedule_work(&ioc->sas_persist_task); break; case MPI_EVENT_SAS_DISCOVERY: - mptscsih_send_discovery(ioc, + mptsas_send_discovery_event(ioc, (EVENT_DATA_SAS_DISCOVERY *)reply->Data); break; default: @@ -2309,7 +2728,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; -out_mptsas_probe: + out_mptsas_probe: mptscsih_remove(pdev); return error; @@ -2319,6 +2738,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) { MPT_ADAPTER *ioc = pci_get_drvdata(pdev); struct mptsas_portinfo *p, *n; + int i; ioc->sas_discovery_ignore_events=1; sas_remove_host(ioc->sh); @@ -2326,8 +2746,9 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) mutex_lock(&ioc->sas_topology_mutex); list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { list_del(&p->list); - if (p->phy_info) - kfree(p->phy_info); + for (i = 0 ; i < p->num_phys ; i++) + mptsas_port_delete(p->phy_info[i].port_details); + kfree(p->phy_info); kfree(p); } mutex_unlock(&ioc->sas_topology_mutex); -- cgit v1.2.3 From 87cf89866790a373edcf88c12b64d6d38560acdd Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 27 Jun 2006 16:09:26 -0600 Subject: [SCSI] mptsas: Adding 1078 ROC support * Adding 1078 ROC (Raid On Chip) Support - New host adapter * Moving all PCI Vendor/Device ids to using internal defines; a request from Christoph/James B. some time ago for when the next chip was added. * Removing SAS 1066/1066E Vendor/Device IDs, as there are no plans to manufacture that controller. Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 60 ++++++++++++++++++++++++++-------------- drivers/message/fusion/mptbase.h | 3 +- drivers/message/fusion/mptfc.c | 16 +++++------ drivers/message/fusion/mptsas.c | 12 ++++---- drivers/message/fusion/mptspi.c | 4 +-- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 12dd8d493ee..8ac77caf933 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1220,31 +1220,25 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) port = psize = 0; for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) { + if (psize) + continue; /* Get I/O space! */ port = pci_resource_start(pdev, ii); psize = pci_resource_len(pdev,ii); } else { + if (msize) + continue; /* Get memmap */ mem_phys = pci_resource_start(pdev, ii); msize = pci_resource_len(pdev,ii); - break; } } ioc->mem_size = msize; - if (ii == DEVICE_COUNT_RESOURCE) { - printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n"); - kfree(ioc); - return -EINVAL; - } - - dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize)); - dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize)); - mem = NULL; /* Get logical ptr for PciMem0 space */ /*mem = ioremap(mem_phys, msize);*/ - mem = ioremap(mem_phys, 0x100); + mem = ioremap(mem_phys, msize); if (mem == NULL) { printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n"); kfree(ioc); @@ -1344,11 +1338,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->bus_type = SAS; ioc->errata_flag_1064 = 1; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) { - ioc->prod_name = "LSISAS1066"; - ioc->bus_type = SAS; - ioc->errata_flag_1064 = 1; - } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) { ioc->prod_name = "LSISAS1068"; ioc->bus_type = SAS; @@ -1358,14 +1347,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->prod_name = "LSISAS1064E"; ioc->bus_type = SAS; } - else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) { - ioc->prod_name = "LSISAS1066E"; - ioc->bus_type = SAS; - } else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) { ioc->prod_name = "LSISAS1068E"; ioc->bus_type = SAS; } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + ioc->prod_name = "LSISAS1078"; + ioc->bus_type = SAS; + } if (ioc->errata_flag_1064) pci_disable_io_access(pdev); @@ -3185,6 +3174,37 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) u32 diag1val = 0; #endif + if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) { + drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset " + "address=%p\n", ioc->name, __FUNCTION__, + &ioc->chip->Doorbell, &ioc->chip->Reset_1078)); + CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07); + if (sleepFlag == CAN_SLEEP) + msleep(1); + else + mdelay(1); + + for (count = 0; count < 60; count ++) { + doorbell = CHIPREG_READ32(&ioc->chip->Doorbell); + doorbell &= MPI_IOC_STATE_MASK; + + drsprintk((MYIOC_s_INFO_FMT + "looking for READY STATE: doorbell=%x" + " count=%d\n", + ioc->name, doorbell, count)); + if (doorbell == MPI_IOC_STATE_READY) { + return 0; + } + + /* wait 1 sec */ + if (sleepFlag == CAN_SLEEP) + msleep(1000); + else + mdelay(1000); + } + return -1; + } + /* Clear any existing interrupts */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index ddef586e09e..7bf0855f934 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -308,7 +308,8 @@ typedef struct _SYSIF_REGS u32 HostIndex; /* 50 Host Index register */ u32 Reserved4[15]; /* 54-8F */ u32 Fubar; /* 90 For Fubar usage */ - u32 Reserved5[27]; /* 94-FF */ + u32 Reserved5[1050];/* 94-10F8 */ + u32 Reset_1078; /* 10FC Reset 1078 */ } SYSIF_REGS; /* diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 74714e5bcf0..d0141ccbb7a 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -132,21 +132,21 @@ static struct scsi_host_template mptfc_driver_template = { */ static struct pci_device_id mptfc_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 0877023cc79..bc36f5fdb53 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2757,17 +2757,15 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) } static struct pci_device_id mptsas_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E, - PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 3201de05394..0a1ff762205 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -775,9 +775,9 @@ static struct spi_function_template mptspi_transport_functions = { */ static struct pci_device_id mptspi_pci_table[] = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030, PCI_ANY_ID, PCI_ANY_ID }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035, + { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035, PCI_ANY_ID, PCI_ANY_ID }, {0} /* Terminating entry */ }; -- cgit v1.2.3 From dc6a78f1af10d28fb8c395034ae1e099b85c05b0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 27 Jun 2006 22:01:28 -0700 Subject: [SCSI] atp870u: reduce huge stack usage The atp870u driver is the largest stack eater reported by checkstack (on x86_864, allmodconfig). This converts the offending function to kmalloc+kfree struct atp_unit instead of allocating it on the stack. Was: 0x0000164c atp870u_probe [atp870u]: 3176 Now: 0x0000164c atp870u_probe [atp870u]: 408 Signed-off-by: Randy Dunlap Signed-off-by: James Bottomley --- drivers/scsi/atp870u.c | 157 ++++++++++++++++++++++++++----------------------- 1 file changed, 83 insertions(+), 74 deletions(-) diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 3ee4d4d3f44..69e6e9821c9 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -2625,29 +2625,32 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) unsigned int base_io, tmport, error,n; unsigned char host_id; struct Scsi_Host *shpnt = NULL; - struct atp_unit atp_dev, *p; + struct atp_unit *atpdev, *p; unsigned char setupdata[2][16]; int count = 0; - + + atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL); + if (!atpdev) + return -ENOMEM; + if (pci_enable_device(pdev)) - return -EIO; + goto err_eio; if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_INFO "atp870u: use 32bit DMA mask.\n"); } else { printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); - return -EIO; + goto err_eio; } - memset(&atp_dev, 0, sizeof atp_dev); /* * It's probably easier to weed out some revisions like * this than via the PCI device table */ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); - if (atp_dev.chip_ver < 2) - return -EIO; + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); + if (atpdev->chip_ver < 2) + goto err_eio; } switch (ent->device) { @@ -2656,15 +2659,15 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) case ATP880_DEVID1: case ATP880_DEVID2: case ATP885_DEVID: - atp_dev.chip_ver = 0x04; + atpdev->chip_ver = 0x04; default: break; } base_io = pci_resource_start(pdev, 0); base_io &= 0xfffffff8; - + if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) { - error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver); pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803 host_id = inb(base_io + 0x39); @@ -2672,17 +2675,17 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d" " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io + 0x40; - atp_dev.pciport[0] = base_io + 0x28; - atp_dev.dev_id = ent->device; - atp_dev.host_id[0] = host_id; + atpdev->ioport[0] = base_io + 0x40; + atpdev->pciport[0] = base_io + 0x28; + atpdev->dev_id = ent->device; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x13; - atp_dev.global_map[0] = inb(tmport); + atpdev->global_map[0] = inb(tmport); tmport += 0x07; - atp_dev.ultra_map[0] = inw(tmport); + atpdev->ultra_map[0] = inw(tmport); n = 0x3f09; next_fblk_880: @@ -2695,57 +2698,57 @@ next_fblk_880: if (inb(base_io + 0x30) == 0xff) goto flash_ok_880; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[0][m++] = inb(base_io + 0x30); - atp_dev.sp[0][m++] = inb(base_io + 0x31); - atp_dev.sp[0][m++] = inb(base_io + 0x32); - atp_dev.sp[0][m++] = inb(base_io + 0x33); + atpdev->sp[0][m++] = inb(base_io + 0x30); + atpdev->sp[0][m++] = inb(base_io + 0x31); + atpdev->sp[0][m++] = inb(base_io + 0x32); + atpdev->sp[0][m++] = inb(base_io + 0x33); n += 0x0018; goto next_fblk_880; flash_ok_880: outw(0, base_io + 0x34); - atp_dev.ultra_map[0] = 0; - atp_dev.async[0] = 0; + atpdev->ultra_map[0] = 0; + atpdev->async[0] = 0; for (k = 0; k < 16; k++) { n = 1; n = n << k; - if (atp_dev.sp[0][k] > 1) { - atp_dev.ultra_map[0] |= n; + if (atpdev->sp[0][k] > 1) { + atpdev->ultra_map[0] |= n; } else { - if (atp_dev.sp[0][k] == 0) - atp_dev.async[0] |= n; + if (atpdev->sp[0][k] == 0) + atpdev->async[0] |= n; } } - atp_dev.async[0] = ~(atp_dev.async[0]); - outb(atp_dev.global_map[0], base_io + 0x35); + atpdev->async[0] = ~(atpdev->async[0]); + outb(atpdev->global_map[0], base_io + 0x35); shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) { printk(KERN_ERR "Unable to allocate tables for Acard controller\n"); goto unregister; @@ -2798,24 +2801,24 @@ flash_ok_880: printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n" , base_io, pdev->irq); - atp_dev.pdev = pdev; - atp_dev.dev_id = ent->device; - atp_dev.baseport = base_io; - atp_dev.ioport[0] = base_io + 0x80; - atp_dev.ioport[1] = base_io + 0xc0; - atp_dev.pciport[0] = base_io + 0x40; - atp_dev.pciport[1] = base_io + 0x50; + atpdev->pdev = pdev; + atpdev->dev_id = ent->device; + atpdev->baseport = base_io; + atpdev->ioport[0] = base_io + 0x80; + atpdev->ioport[1] = base_io + 0xc0; + atpdev->pciport[0] = base_io + 0x40; + atpdev->pciport[1] = base_io + 0x50; shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof(struct atp_unit)); + memcpy(p, atpdev, sizeof(struct atp_unit)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -2974,33 +2977,33 @@ flash_ok_885: printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d " "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atp_dev.ioport[0] = base_io; - atp_dev.pciport[0] = base_io + 0x20; - atp_dev.dev_id = ent->device; + atpdev->ioport[0] = base_io; + atpdev->pciport[0] = base_io + 0x20; + atpdev->dev_id = ent->device; host_id &= 0x07; - atp_dev.host_id[0] = host_id; + atpdev->host_id[0] = host_id; tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); + atpdev->scam_on = inb(tmport); tmport += 0x0b; - atp_dev.global_map[0] = inb(tmport++); - atp_dev.ultra_map[0] = inw(tmport); + atpdev->global_map[0] = inb(tmport++); + atpdev->ultra_map[0] = inw(tmport); - if (atp_dev.ultra_map[0] == 0) { - atp_dev.scam_on = 0x00; - atp_dev.global_map[0] = 0x20; - atp_dev.ultra_map[0] = 0xffff; + if (atpdev->ultra_map[0] == 0) { + atpdev->scam_on = 0x00; + atpdev->global_map[0] = 0x20; + atpdev->ultra_map[0] = 0xffff; } shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) - return -ENOMEM; + goto err_nomem; p = (struct atp_unit *)&shpnt->hostdata; - atp_dev.host = shpnt; - atp_dev.pdev = pdev; + atpdev->host = shpnt; + atpdev->pdev = pdev; pci_set_drvdata(pdev, p); - memcpy(p, &atp_dev, sizeof atp_dev); + memcpy(p, atpdev, sizeof(*atpdev)); if (atp870u_init_tables(shpnt) < 0) goto unregister; @@ -3010,7 +3013,7 @@ flash_ok_885: } spin_lock_irqsave(shpnt->host_lock, flags); - if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ + if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ tmport = base_io + 0x3e; outb(0x00, tmport); } @@ -3044,7 +3047,7 @@ flash_ok_885: outb((inb(tmport) & 0xef), tmport); tmport++; outb((inb(tmport) | 0x20), tmport); - if (atp_dev.chip_ver == 4) + if (atpdev->chip_ver == 4) shpnt->max_id = 16; else shpnt->max_id = 8; @@ -3093,6 +3096,12 @@ unregister: printk("atp870u_prob:unregister\n"); scsi_host_put(shpnt); return -1; +err_eio: + kfree(atpdev); + return -EIO; +err_nomem: + kfree(atpdev); + return -ENOMEM; } /* The abort command does not leave the device in a clean state where -- cgit v1.2.3 From 332959cb521af6bb0281c7aae797f1f91dcb4c42 Mon Sep 17 00:00:00 2001 From: Martin Habets Date: Wed, 28 Jun 2006 15:40:36 +0100 Subject: [SCSI] st: remove unused st_buffer.in_use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I noticed that in_use in st_buffer is not used. The patch below against 2.6.17-rc3 removes it, assuming there is no future use for it. It was tested in a sparc SS20 with a DLT4000. Signed-off-by: Martin Habets Acked-by: Kai Mäkisara Signed-off-by: James Bottomley --- drivers/scsi/st.c | 1 - drivers/scsi/st.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index b5218fc0ac8..756ceb93ddc 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3599,7 +3599,6 @@ static struct st_buffer * tb->use_sg = max_sg; tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); - tb->in_use = 1; tb->dma = need_dma; tb->buffer_size = got; diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 411209048d7..05a5cae126e 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -31,7 +31,6 @@ struct st_request { /* The tape buffer descriptor. */ struct st_buffer { - unsigned char in_use; unsigned char dma; /* DMA-able buffer */ unsigned char do_dio; /* direct i/o set up? */ int buffer_size; -- cgit v1.2.3 From 01cb225dad8da2e717356fab03240e2f4a8d01bf Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:22 -0500 Subject: [SCSI] iscsi: add target discvery event to transport class Patch from david.somayajulu@qlogic.com: Add target discovery event. We may have a setup where the iscsi traffic is on a different netowrk than the other network traffic. In this case we will want to do discovery though the iscsi card. This patch adds a event to the transport class that can be used by hw iscsi cards that support this. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 18 ++++++++++++++++++ include/scsi/iscsi_if.h | 37 +++++++++++++++++++++++++++++++++++++ include/scsi/scsi_transport_iscsi.h | 2 ++ 3 files changed, 57 insertions(+) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 5569fdcfd62..99e76d45829 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -977,6 +977,21 @@ iscsi_if_transport_ep(struct iscsi_transport *transport, return rc; } +static int +iscsi_tgt_dscvr(struct iscsi_transport *transport, + struct iscsi_uevent *ev) +{ + struct sockaddr *dst_addr; + + if (!transport->tgt_dscvr) + return -EINVAL; + + dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); + return transport->tgt_dscvr(ev->u.tgt_dscvr.type, + ev->u.tgt_dscvr.host_no, + ev->u.tgt_dscvr.enable, dst_addr); +} + static int iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { @@ -1065,6 +1080,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); break; + case ISCSI_UEVENT_TGT_DSCVR: + err = iscsi_tgt_dscvr(transport, ev); + break; default: err = -EINVAL; break; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 253797c6009..8813f0f4c62 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -47,12 +47,20 @@ enum iscsi_uevent_e { ISCSI_UEVENT_TRANSPORT_EP_POLL = UEVENT_BASE + 13, ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT = UEVENT_BASE + 14, + ISCSI_UEVENT_TGT_DSCVR = UEVENT_BASE + 15, + /* up events */ ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, }; +enum iscsi_tgt_dscvr { + ISCSI_TGT_DSCVR_SEND_TARGETS = 1, + ISCSI_TGT_DSCVR_ISNS = 2, + ISCSI_TGT_DSCVR_SLP = 3, +}; + struct iscsi_uevent { uint32_t type; /* k/u events type */ uint32_t iferror; /* carries interface or resource errors */ @@ -116,6 +124,17 @@ struct iscsi_uevent { struct msg_transport_disconnect { uint64_t ep_handle; } ep_disconnect; + struct msg_tgt_dscvr { + enum iscsi_tgt_dscvr type; + uint32_t host_no; + /* + * enable = 1 to establish a new connection + * with the server. enable = 0 to disconnect + * from the server. Used primarily to switch + * from one iSNS server to another. + */ + uint32_t enable; + } tgt_dscvr; } u; union { /* messages k -> u */ @@ -141,6 +160,24 @@ struct iscsi_uevent { struct msg_transport_connect_ret { uint64_t handle; } ep_connect_ret; + struct msg_tgt_dscvr_ret { + /* + * session/connection pair used to reference + * the connection to server + */ + uint32_t sid; + uint32_t cid; + union { + struct isns { + /* port # for conn to iSNS server */ + uint16_t isns_port; + /* listening port to receive SCNs */ + uint16_t scn_port; + /* listening port to receive ESIs */ + uint16_t esi_port; + } isns_attrib; + } u; + } tgt_dscvr_ret; } r; } __attribute__ ((aligned (sizeof(uint64_t)))); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b684426a590..b95151aec60 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -127,6 +127,8 @@ struct iscsi_transport { uint64_t *ep_handle); int (*ep_poll) (uint64_t ep_handle, int timeout_ms); void (*ep_disconnect) (uint64_t ep_handle); + int (*tgt_dscvr) (enum iscsi_tgt_dscvr type, uint32_t host_no, + uint32_t enable, struct sockaddr *dst_addr); }; /* -- cgit v1.2.3 From a54a52caad4bd6166cb7fa64e4e93031fa2fda5d Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:23 -0500 Subject: [SCSI] iscsi: fixup set/get param functions Reduce duplication in the software iscsi_transport modules by adding a libiscsi function to handle the common grunt work. This also has the drivers return specifc -EXXX values for different errors so userspace can finally handle them in a sane way. Also just pass the sysfs buffers to the drivers so HW iscsi can get/set its string values, like targetname, and initiatorname. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 179 ++++++++++++++++++++++++++++++ drivers/scsi/scsi_transport_iscsi.c | 210 ++++++++---------------------------- include/scsi/libiscsi.h | 15 ++- include/scsi/scsi_transport_iscsi.h | 29 ++--- 4 files changed, 246 insertions(+), 187 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 2673a11a949..7c76a989b21 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1697,6 +1697,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session, } EXPORT_SYMBOL_GPL(iscsi_conn_bind); + +int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct iscsi_session *session = conn->session; + uint32_t value; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + sscanf(buf, "%d", &conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + sscanf(buf, "%d", &conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + sscanf(buf, "%d", &conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + sscanf(buf, "%d", &conn->datadgst_en); + break; + case ISCSI_PARAM_INITIAL_R2T_EN: + sscanf(buf, "%d", &session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + sscanf(buf, "%d", &session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + sscanf(buf, "%d", &session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + sscanf(buf, "%d", &session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + sscanf(buf, "%d", &session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + sscanf(buf, "%d", &session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + sscanf(buf, "%d", &session->erl); + break; + case ISCSI_PARAM_IFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_OFMARKER_EN: + sscanf(buf, "%d", &value); + BUG_ON(value); + break; + case ISCSI_PARAM_EXP_STATSN: + sscanf(buf, "%u", &conn->exp_statsn); + break; + case ISCSI_PARAM_TARGET_NAME: + /* this should not change between logins */ + if (session->targetname) + break; + + session->targetname = kstrdup(buf, GFP_KERNEL); + if (!session->targetname) + return -ENOMEM; + break; + case ISCSI_PARAM_TPGT: + sscanf(buf, "%d", &session->tpgt); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + sscanf(buf, "%d", &conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + /* + * this is the address returned in discovery so it should + * not change between logins. + */ + if (conn->persistent_address) + break; + + conn->persistent_address = kstrdup(buf, GFP_KERNEL); + if (!conn->persistent_address) + return -ENOMEM; + break; + default: + return -ENOSYS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(iscsi_set_param); + +int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + enum iscsi_param param, char *buf) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct iscsi_session *session = iscsi_hostdata(shost->hostdata); + int len; + + switch(param) { + case ISCSI_PARAM_INITIAL_R2T_EN: + len = sprintf(buf, "%d\n", session->initial_r2t_en); + break; + case ISCSI_PARAM_MAX_R2T: + len = sprintf(buf, "%hu\n", session->max_r2t); + break; + case ISCSI_PARAM_IMM_DATA_EN: + len = sprintf(buf, "%d\n", session->imm_data_en); + break; + case ISCSI_PARAM_FIRST_BURST: + len = sprintf(buf, "%u\n", session->first_burst); + break; + case ISCSI_PARAM_MAX_BURST: + len = sprintf(buf, "%u\n", session->max_burst); + break; + case ISCSI_PARAM_PDU_INORDER_EN: + len = sprintf(buf, "%d\n", session->pdu_inorder_en); + break; + case ISCSI_PARAM_DATASEQ_INORDER_EN: + len = sprintf(buf, "%d\n", session->dataseq_inorder_en); + break; + case ISCSI_PARAM_ERL: + len = sprintf(buf, "%d\n", session->erl); + break; + case ISCSI_PARAM_TARGET_NAME: + len = sprintf(buf, "%s\n", session->targetname); + break; + case ISCSI_PARAM_TPGT: + len = sprintf(buf, "%d\n", session->tpgt); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_session_get_param); + +int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + int len; + + switch(param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_recv_dlength); + break; + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + len = sprintf(buf, "%u\n", conn->max_xmit_dlength); + break; + case ISCSI_PARAM_HDRDGST_EN: + len = sprintf(buf, "%d\n", conn->hdrdgst_en); + break; + case ISCSI_PARAM_DATADGST_EN: + len = sprintf(buf, "%d\n", conn->datadgst_en); + break; + case ISCSI_PARAM_IFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ifmarker_en); + break; + case ISCSI_PARAM_OFMARKER_EN: + len = sprintf(buf, "%d\n", conn->ofmarker_en); + break; + case ISCSI_PARAM_EXP_STATSN: + len = sprintf(buf, "%u\n", conn->exp_statsn); + break; + case ISCSI_PARAM_PERSISTENT_PORT: + len = sprintf(buf, "%d\n", conn->persistent_port); + break; + case ISCSI_PARAM_PERSISTENT_ADDRESS: + len = sprintf(buf, "%s\n", conn->persistent_address); + break; + default: + return -ENOSYS; + } + + return len; +} +EXPORT_SYMBOL_GPL(iscsi_conn_get_param); + MODULE_AUTHOR("Mike Christie"); MODULE_DESCRIPTION("iSCSI library functions"); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 99e76d45829..147c854e1d4 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -233,7 +233,6 @@ static void iscsi_session_release(struct device *dev) shost = iscsi_session_to_shost(session); scsi_host_put(shost); - kfree(session->targetname); kfree(session); module_put(transport->owner); } @@ -388,7 +387,6 @@ static void iscsi_conn_release(struct device *dev) struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; - kfree(conn->persistent_address); kfree(conn); put_device(parent); } @@ -877,23 +875,13 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev return 0; } -static void -iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data) -{ - if (ev->u.set_param.len != sizeof(uint32_t)) - BUG(); - memcpy(value, data, min_t(uint32_t, sizeof(uint32_t), - ev->u.set_param.len)); -} - static int iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) { char *data = (char*)ev + sizeof(*ev); struct iscsi_cls_conn *conn; struct iscsi_cls_session *session; - int err = 0; - uint32_t value = 0; + int err = 0, value = 0; session = iscsi_session_lookup(ev->u.set_param.sid); conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); @@ -902,42 +890,13 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) switch (ev->u.set_param.param) { case ISCSI_PARAM_SESS_RECOVERY_TMO: - iscsi_copy_param(ev, &value, data); + sscanf(data, "%d", &value); if (value != 0) session->recovery_tmo = value; break; - case ISCSI_PARAM_TARGET_NAME: - /* this should not change between logins */ - if (session->targetname) - return 0; - - session->targetname = kstrdup(data, GFP_KERNEL); - if (!session->targetname) - return -ENOMEM; - break; - case ISCSI_PARAM_TPGT: - iscsi_copy_param(ev, &value, data); - session->tpgt = value; - break; - case ISCSI_PARAM_PERSISTENT_PORT: - iscsi_copy_param(ev, &value, data); - conn->persistent_port = value; - break; - case ISCSI_PARAM_PERSISTENT_ADDRESS: - /* - * this is the address returned in discovery so it should - * not change between logins. - */ - if (conn->persistent_address) - return 0; - - conn->persistent_address = kstrdup(data, GFP_KERNEL); - if (!conn->persistent_address) - return -ENOMEM; - break; default: - iscsi_copy_param(ev, &value, data); - err = transport->set_param(conn, ev->u.set_param.param, value); + err = transport->set_param(conn, ev->u.set_param.param, + data, ev->u.set_param.len); } return err; @@ -1165,49 +1124,31 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name = \ /* * iSCSI connection attrs */ -#define iscsi_conn_int_attr_show(param, format) \ +#define iscsi_conn_attr_show(param) \ static ssize_t \ -show_conn_int_param_##param(struct class_device *cdev, char *buf) \ +show_conn_param_##param(struct class_device *cdev, char *buf) \ { \ - uint32_t value = 0; \ struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ struct iscsi_transport *t = conn->transport; \ - \ - t->get_conn_param(conn, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ + return t->get_conn_param(conn, param, buf); \ } -#define iscsi_conn_int_attr(field, param, format) \ - iscsi_conn_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \ +#define iscsi_conn_attr(field, param) \ + iscsi_conn_attr_show(param) \ +static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \ NULL); -iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u"); -iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u"); -iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d"); -iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d"); -iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d"); -iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d"); -iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d"); -iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d"); -iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u"); - -#define iscsi_conn_str_attr_show(param) \ -static ssize_t \ -show_conn_str_param_##param(struct class_device *cdev, char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - struct iscsi_transport *t = conn->transport; \ - return t->get_conn_str_param(conn, param, buf); \ -} - -#define iscsi_conn_str_attr(field, param) \ - iscsi_conn_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \ - NULL); - -iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); -iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); +iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); +iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); +iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN); +iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN); +iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN); +iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN); +iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT); +iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT); +iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); +iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); +iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS); #define iscsi_cdev_to_session(_cdev) \ iscsi_dev_to_session(_cdev->dev) @@ -1215,61 +1156,36 @@ iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS); /* * iSCSI session attrs */ -#define iscsi_session_int_attr_show(param, format) \ -static ssize_t \ -show_session_int_param_##param(struct class_device *cdev, char *buf) \ -{ \ - uint32_t value = 0; \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ - struct iscsi_transport *t = session->transport; \ - \ - t->get_session_param(session, param, &value); \ - return snprintf(buf, 20, format"\n", value); \ -} - -#define iscsi_session_int_attr(field, param, format) \ - iscsi_session_int_attr_show(param, format) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \ - NULL); - -iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d"); -iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu"); -iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d"); -iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u"); -iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u"); -iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d"); -iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d"); -iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d"); -iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d"); - -#define iscsi_session_str_attr_show(param) \ +#define iscsi_session_attr_show(param) \ static ssize_t \ -show_session_str_param_##param(struct class_device *cdev, char *buf) \ +show_session_param_##param(struct class_device *cdev, char *buf) \ { \ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ struct iscsi_transport *t = session->transport; \ - return t->get_session_str_param(session, param, buf); \ + return t->get_session_param(session, param, buf); \ } -#define iscsi_session_str_attr(field, param) \ - iscsi_session_str_attr_show(param) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \ +#define iscsi_session_attr(field, param) \ + iscsi_session_attr_show(param) \ +static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \ NULL); -iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME); +iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN); +iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T); +iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN); +iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST); +iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST); +iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN); +iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN); +iscsi_session_attr(erl, ISCSI_PARAM_ERL); +iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT); -/* - * Private session and conn attrs. userspace uses several iscsi values - * to identify each session between reboots. Some of these values may not - * be present in the iscsi_transport/LLD driver becuase userspace handles - * login (and failback for login redirect) so for these type of drivers - * the class manages the attrs and values for the iscsi_transport/LLD - */ #define iscsi_priv_session_attr_show(field, format) \ static ssize_t \ -show_priv_session_##field(struct class_device *cdev, char *buf) \ +show_priv_session_##field(struct class_device *cdev, char *buf) \ { \ - struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \ + struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\ return sprintf(buf, format"\n", session->field); \ } @@ -1277,31 +1193,15 @@ show_priv_session_##field(struct class_device *cdev, char *buf) \ iscsi_priv_session_attr_show(field, format) \ static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \ NULL) -iscsi_priv_session_attr(targetname, "%s"); -iscsi_priv_session_attr(tpgt, "%d"); iscsi_priv_session_attr(recovery_tmo, "%d"); -#define iscsi_priv_conn_attr_show(field, format) \ -static ssize_t \ -show_priv_conn_##field(struct class_device *cdev, char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \ - return sprintf(buf, format"\n", conn->field); \ -} - -#define iscsi_priv_conn_attr(field, format) \ - iscsi_priv_conn_attr_show(field, format) \ -static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \ - NULL) -iscsi_priv_conn_attr(persistent_address, "%s"); -iscsi_priv_conn_attr(persistent_port, "%d"); - #define SETUP_PRIV_SESSION_RD_ATTR(field) \ do { \ priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \ count++; \ } while (0) + #define SETUP_SESSION_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1310,12 +1210,6 @@ do { \ } \ } while (0) -#define SETUP_PRIV_CONN_RD_ATTR(field) \ -do { \ - priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \ - count++; \ -} while (0) - #define SETUP_CONN_RD_ATTR(field, param_flag) \ do { \ if (tt->param_mask & param_flag) { \ @@ -1442,16 +1336,8 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS); SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT); SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN); - - if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS) - SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_address); - - if (tt->param_mask & ISCSI_PERSISTENT_PORT) - SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); - else - SETUP_PRIV_CONN_RD_ATTR(persistent_port); + SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS); + SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT); BUG_ON(count > ISCSI_CONN_ATTRS); priv->conn_attrs[count] = NULL; @@ -1471,18 +1357,10 @@ iscsi_register_transport(struct iscsi_transport *tt) SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN); SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN); SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL); + SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); + SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo); - if (tt->param_mask & ISCSI_TARGET_NAME) - SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME); - else - SETUP_PRIV_SESSION_RD_ATTR(targetname); - - if (tt->param_mask & ISCSI_TPGT) - SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT); - else - SETUP_PRIV_SESSION_RD_ATTR(tpgt); - BUG_ON(count > ISCSI_SESSION_ATTRS); priv->session_attrs[count] = NULL; diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index cbf7e58bd6f..ba2760802de 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h @@ -157,6 +157,11 @@ struct iscsi_conn { int max_xmit_dlength; /* target_max_recv_dsl */ int hdrdgst_en; int datadgst_en; + int ifmarker_en; + int ofmarker_en; + /* values userspace uses to id a conn */ + int persistent_port; + char *persistent_address; /* MIB-statistics */ uint64_t txdata_octets; @@ -196,8 +201,8 @@ struct iscsi_session { int pdu_inorder_en; int dataseq_inorder_en; int erl; - int ifmarker_en; - int ofmarker_en; + int tpgt; + char *targetname; /* control data */ struct iscsi_transport *tt; @@ -240,6 +245,10 @@ iscsi_session_setup(struct iscsi_transport *, struct scsi_transport_template *, extern void iscsi_session_teardown(struct iscsi_cls_session *); extern struct iscsi_session *class_to_transport_session(struct iscsi_cls_session *); extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *); +extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen); +extern int iscsi_session_get_param(struct iscsi_cls_session *cls_session, + enum iscsi_param param, char *buf); #define session_to_cls(_sess) \ hostdata_session(_sess->host->hostdata) @@ -255,6 +264,8 @@ extern void iscsi_conn_stop(struct iscsi_cls_conn *, int); extern int iscsi_conn_bind(struct iscsi_cls_session *, struct iscsi_cls_conn *, int); extern void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err); +extern int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf); /* * pdu and task processing diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index b95151aec60..05397058a9b 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -34,6 +34,7 @@ struct iscsi_cls_conn; struct iscsi_conn; struct iscsi_cmd_task; struct iscsi_mgmt_task; +struct sockaddr; /** * struct iscsi_transport - iSCSI Transport template @@ -46,7 +47,12 @@ struct iscsi_mgmt_task; * @bind_conn: associate this connection with existing iSCSI session * and specified transport descriptor * @destroy_conn: destroy inactive iSCSI connection - * @set_param: set iSCSI Data-Path operational parameter + * @set_param: set iSCSI parameter. Return 0 on success, -ENODATA + * when param is not supported, and a -Exx value on other + * error. + * @get_param get iSCSI parameter. Must return number of bytes + * copied to buffer on success, -ENODATA when param + * is not supported, and a -Exx value on other error * @start_conn: set connection to be operational * @stop_conn: suspend/recover/terminate connection * @send_pdu: send iSCSI PDU, Login, Logout, NOP-Out, Reject, Text. @@ -97,15 +103,11 @@ struct iscsi_transport { void (*stop_conn) (struct iscsi_cls_conn *conn, int flag); void (*destroy_conn) (struct iscsi_cls_conn *conn); int (*set_param) (struct iscsi_cls_conn *conn, enum iscsi_param param, - uint32_t value); + char *buf, int buflen); int (*get_conn_param) (struct iscsi_cls_conn *conn, - enum iscsi_param param, uint32_t *value); + enum iscsi_param param, char *buf); int (*get_session_param) (struct iscsi_cls_session *session, - enum iscsi_param param, uint32_t *value); - int (*get_conn_str_param) (struct iscsi_cls_conn *conn, - enum iscsi_param param, char *buf); - int (*get_session_str_param) (struct iscsi_cls_session *session, - enum iscsi_param param, char *buf); + enum iscsi_param param, char *buf); int (*send_pdu) (struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, char *data, uint32_t data_size); void (*get_stats) (struct iscsi_cls_conn *conn, @@ -157,13 +159,6 @@ struct iscsi_cls_conn { struct iscsi_transport *transport; uint32_t cid; /* connection id */ - /* portal/group values we got during discovery */ - char *persistent_address; - int persistent_port; - /* portal/group values we are currently using */ - char *address; - int port; - int active; /* must be accessed with the connlock */ struct device dev; /* sysfs transport/container device */ struct mempool_zone *z_error; @@ -187,10 +182,6 @@ struct iscsi_cls_session { struct list_head host_list; struct iscsi_transport *transport; - /* iSCSI values used as unique id by userspace. */ - char *targetname; - int tpgt; - /* recovery fields */ int recovery_tmo; struct work_struct recovery_work; -- cgit v1.2.3 From 358ff019b89aa530ab6c0dd139d8089c932b103f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:25 -0500 Subject: [SCSI] iscsi: convert iser to new set/get param fns Convert iser to libiscsi get/set param functions. Fix bugs in it returning old error return values and have it expose exp_statsn. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/infiniband/ulp/iser/iscsi_iser.c | 138 ++++--------------------------- 1 file changed, 17 insertions(+), 121 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 4c3f2de2a06..d277fdff5dc 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -438,159 +438,50 @@ iscsi_iser_session_create(struct iscsi_transport *iscsit, } static int -iscsi_iser_conn_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t value) +iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf, int buflen) { - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - - spin_lock_bh(&session->lock); - if (conn->c_stage != ISCSI_CONN_INITIAL_STAGE && - conn->stop_stage != STOP_CONN_RECOVER) { - printk(KERN_ERR "iscsi_iser: can not change parameter [%d]\n", - param); - spin_unlock_bh(&session->lock); - return 0; - } - spin_unlock_bh(&session->lock); + int value; switch (param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: /* TBD */ break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - conn->max_xmit_dlength = value; - break; case ISCSI_PARAM_HDRDGST_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; case ISCSI_PARAM_DATADGST_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "DataDigest wasn't negotiated to None"); return -EPROTO; } break; - case ISCSI_PARAM_INITIAL_R2T_EN: - session->initial_r2t_en = value; - break; - case ISCSI_PARAM_IMM_DATA_EN: - session->imm_data_en = value; - break; - case ISCSI_PARAM_FIRST_BURST: - session->first_burst = value; - break; - case ISCSI_PARAM_MAX_BURST: - session->max_burst = value; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - session->pdu_inorder_en = value; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - session->dataseq_inorder_en = value; - break; - case ISCSI_PARAM_ERL: - session->erl = value; - break; case ISCSI_PARAM_IFMARKER_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "IFMarker wasn't negotiated to No"); return -EPROTO; } break; case ISCSI_PARAM_OFMARKER_EN: + sscanf(buf, "%d", &value); if (value) { printk(KERN_ERR "OFMarker wasn't negotiated to No"); return -EPROTO; } break; default: - break; - } - - return 0; -} - -static int -iscsi_iser_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, uint32_t *value) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct iscsi_session *session = iscsi_hostdata(shost->hostdata); - - switch (param) { - case ISCSI_PARAM_INITIAL_R2T_EN: - *value = session->initial_r2t_en; - break; - case ISCSI_PARAM_MAX_R2T: - *value = session->max_r2t; - break; - case ISCSI_PARAM_IMM_DATA_EN: - *value = session->imm_data_en; - break; - case ISCSI_PARAM_FIRST_BURST: - *value = session->first_burst; - break; - case ISCSI_PARAM_MAX_BURST: - *value = session->max_burst; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - *value = session->pdu_inorder_en; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - *value = session->dataseq_inorder_en; - break; - case ISCSI_PARAM_ERL: - *value = session->erl; - break; - case ISCSI_PARAM_IFMARKER_EN: - *value = 0; - break; - case ISCSI_PARAM_OFMARKER_EN: - *value = 0; - break; - default: - return ISCSI_ERR_PARAM_NOT_FOUND; - } - - return 0; -} - -static int -iscsi_iser_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t *value) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = 0; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = 0; - break; - /*case ISCSI_PARAM_TARGET_RECV_DLENGTH: - *value = conn->target_recv_dlength; - break; - case ISCSI_PARAM_INITIATOR_RECV_DLENGTH: - *value = conn->initiator_recv_dlength; - break;*/ - default: - return ISCSI_ERR_PARAM_NOT_FOUND; + return iscsi_set_param(cls_conn, param, buf, buflen); } return 0; } - static void iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats) { @@ -702,7 +593,12 @@ static struct iscsi_transport iscsi_iser_transport = { ISCSI_FIRST_BURST | ISCSI_MAX_BURST | ISCSI_PDU_INORDER_EN | - ISCSI_DATASEQ_INORDER_EN, + ISCSI_DATASEQ_INORDER_EN | + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .host_template = &iscsi_iser_sht, .conndata_size = sizeof(struct iscsi_conn), .max_lun = ISCSI_ISER_MAX_LUN, @@ -714,9 +610,9 @@ static struct iscsi_transport iscsi_iser_transport = { .create_conn = iscsi_iser_conn_create, .bind_conn = iscsi_iser_conn_bind, .destroy_conn = iscsi_iser_conn_destroy, - .set_param = iscsi_iser_conn_set_param, - .get_conn_param = iscsi_iser_conn_get_param, - .get_session_param = iscsi_iser_session_get_param, + .set_param = iscsi_iser_set_param, + .get_conn_param = iscsi_conn_get_param, + .get_session_param = iscsi_session_get_param, .start_conn = iscsi_iser_conn_start, .stop_conn = iscsi_conn_stop, /* these are called as part of conn recovery */ -- cgit v1.2.3 From 5c75b7fcf0c0e3921391fd93f5fa58ec9a6c428f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:26 -0500 Subject: [SCSI] iscsi: convert iscsi_tcp to new set/get param fns Convert iscsi_tcp to new lib functions. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/iscsi_tcp.c | 152 ++++++++--------------------------------------- 1 file changed, 24 insertions(+), 128 deletions(-) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index b4743a9ecc8..848fb2aa4ca 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -2130,19 +2130,21 @@ iscsi_r2tpool_free(struct iscsi_session *session) static int iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, - uint32_t value) + char *buf, int buflen) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_session *session = conn->session; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + int value; switch(param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: { char *saveptr = tcp_conn->data; gfp_t flags = GFP_KERNEL; + sscanf(buf, "%d", &value); if (tcp_conn->data_size >= value) { - conn->max_recv_dlength = value; + iscsi_set_param(cls_conn, param, buf, buflen); break; } @@ -2165,15 +2167,12 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, else free_pages((unsigned long)saveptr, get_order(tcp_conn->data_size)); - conn->max_recv_dlength = value; + iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->data_size = value; - } - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - conn->max_xmit_dlength = value; break; + } case ISCSI_PARAM_HDRDGST_EN: - conn->hdrdgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); tcp_conn->hdr_size = sizeof(struct iscsi_hdr); if (conn->hdrdgst_en) { tcp_conn->hdr_size += sizeof(__u32); @@ -2197,7 +2196,7 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, } break; case ISCSI_PARAM_DATADGST_EN: - conn->datadgst_en = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (conn->datadgst_en) { if (!tcp_conn->data_tx_tfm) tcp_conn->data_tx_tfm = @@ -2220,121 +2219,36 @@ iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param, tcp_conn->sendpage = conn->datadgst_en ? sock_no_sendpage : tcp_conn->sock->ops->sendpage; break; - case ISCSI_PARAM_INITIAL_R2T_EN: - session->initial_r2t_en = value; - break; case ISCSI_PARAM_MAX_R2T: + sscanf(buf, "%d", &value); if (session->max_r2t == roundup_pow_of_two(value)) break; iscsi_r2tpool_free(session); - session->max_r2t = value; + iscsi_set_param(cls_conn, param, buf, buflen); if (session->max_r2t & (session->max_r2t - 1)) session->max_r2t = roundup_pow_of_two(session->max_r2t); if (iscsi_r2tpool_alloc(session)) return -ENOMEM; break; - case ISCSI_PARAM_IMM_DATA_EN: - session->imm_data_en = value; - break; - case ISCSI_PARAM_FIRST_BURST: - session->first_burst = value; - break; - case ISCSI_PARAM_MAX_BURST: - session->max_burst = value; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - session->pdu_inorder_en = value; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - session->dataseq_inorder_en = value; - break; - case ISCSI_PARAM_ERL: - session->erl = value; - break; - case ISCSI_PARAM_IFMARKER_EN: - BUG_ON(value); - session->ifmarker_en = value; - break; - case ISCSI_PARAM_OFMARKER_EN: - BUG_ON(value); - session->ofmarker_en = value; - break; - case ISCSI_PARAM_EXP_STATSN: - conn->exp_statsn = value; - break; - default: - break; - } - - return 0; -} - -static int -iscsi_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, uint32_t *value) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct iscsi_session *session = iscsi_hostdata(shost->hostdata); - - switch(param) { - case ISCSI_PARAM_INITIAL_R2T_EN: - *value = session->initial_r2t_en; - break; - case ISCSI_PARAM_MAX_R2T: - *value = session->max_r2t; - break; - case ISCSI_PARAM_IMM_DATA_EN: - *value = session->imm_data_en; - break; - case ISCSI_PARAM_FIRST_BURST: - *value = session->first_burst; - break; - case ISCSI_PARAM_MAX_BURST: - *value = session->max_burst; - break; - case ISCSI_PARAM_PDU_INORDER_EN: - *value = session->pdu_inorder_en; - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - *value = session->dataseq_inorder_en; - break; - case ISCSI_PARAM_ERL: - *value = session->erl; - break; - case ISCSI_PARAM_IFMARKER_EN: - *value = session->ifmarker_en; - break; - case ISCSI_PARAM_OFMARKER_EN: - *value = session->ofmarker_en; - break; default: - return -EINVAL; + return iscsi_set_param(cls_conn, param, buf, buflen); } return 0; } static int -iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, uint32_t *value) +iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, + enum iscsi_param param, char *buf) { struct iscsi_conn *conn = cls_conn->dd_data; struct iscsi_tcp_conn *tcp_conn = conn->dd_data; struct inet_sock *inet; + struct ipv6_pinfo *np; + struct sock *sk; + int len; switch(param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - *value = conn->max_recv_dlength; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - *value = conn->max_xmit_dlength; - break; - case ISCSI_PARAM_HDRDGST_EN: - *value = conn->hdrdgst_en; - break; - case ISCSI_PARAM_DATADGST_EN: - *value = conn->datadgst_en; - break; case ISCSI_PARAM_CONN_PORT: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2343,30 +2257,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, } inet = inet_sk(tcp_conn->sock->sk); - *value = be16_to_cpu(inet->dport); + len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport)); mutex_unlock(&conn->xmitmutex); - case ISCSI_PARAM_EXP_STATSN: - *value = conn->exp_statsn; break; - default: - return -EINVAL; - } - - return 0; -} - -static int -iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct sock *sk; - struct inet_sock *inet; - struct ipv6_pinfo *np; - int len = 0; - - switch (param) { case ISCSI_PARAM_CONN_ADDRESS: mutex_lock(&conn->xmitmutex); if (!tcp_conn->sock) { @@ -2388,7 +2281,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn, mutex_unlock(&conn->xmitmutex); break; default: - return -EINVAL; + return iscsi_conn_get_param(cls_conn, param, buf); } return len; @@ -2501,7 +2394,11 @@ static struct iscsi_transport iscsi_tcp_transport = { ISCSI_ERL | ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | - ISCSI_EXP_STATSN, + ISCSI_EXP_STATSN | + ISCSI_PERSISTENT_PORT | + ISCSI_PERSISTENT_ADDRESS | + ISCSI_TARGET_NAME | + ISCSI_TPGT, .host_template = &iscsi_sht, .conndata_size = sizeof(struct iscsi_conn), .max_conn = 1, @@ -2514,8 +2411,7 @@ static struct iscsi_transport iscsi_tcp_transport = { .bind_conn = iscsi_tcp_conn_bind, .destroy_conn = iscsi_tcp_conn_destroy, .set_param = iscsi_conn_set_param, - .get_conn_param = iscsi_conn_get_param, - .get_conn_str_param = iscsi_conn_get_str_param, + .get_conn_param = iscsi_tcp_conn_get_param, .get_session_param = iscsi_session_get_param, .start_conn = iscsi_conn_start, .stop_conn = iscsi_conn_stop, -- cgit v1.2.3 From f53a88da18e3c04c3ade07bc5eff520ee4259c3e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:27 -0500 Subject: [SCSI] iscsi: fix session refcouting iscsi_tcp and iser cannot be rmmod from the kernel when sessions are running because session removal is driven from userspace. For those modules we get a module reference when a session is created then drop it when the session is removed. For qla4xxx, they can jsut remove the sessions from the pci remove function like normal HW drivers, so this patch moves the module reference from the transport class functions shared by all drivers to the libiscsi functions only used be software iscsi modules. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 8 +++++++- drivers/scsi/scsi_transport_iscsi.c | 10 ++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 7c76a989b21..7e6e031cc41 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1287,13 +1287,18 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (scsi_add_host(shost, NULL)) goto add_host_fail; + if (!try_module_get(iscsit->owner)) + goto cls_session_fail; + cls_session = iscsi_create_session(shost, iscsit, 0); if (!cls_session) - goto cls_session_fail; + goto module_put; *(unsigned long*)shost->hostdata = (unsigned long)cls_session; return cls_session; +module_put: + module_put(iscsit->owner); cls_session_fail: scsi_remove_host(shost); add_host_fail: @@ -1325,6 +1330,7 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session) iscsi_destroy_session(cls_session); scsi_host_put(shost); + module_put(cls_session->transport->owner); } EXPORT_SYMBOL_GPL(iscsi_session_teardown); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 147c854e1d4..8717ff51ba4 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -228,13 +228,11 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) static void iscsi_session_release(struct device *dev) { struct iscsi_cls_session *session = iscsi_dev_to_session(dev); - struct iscsi_transport *transport = session->transport; struct Scsi_Host *shost; shost = iscsi_session_to_shost(session); scsi_host_put(shost); kfree(session); - module_put(transport->owner); } static int iscsi_is_session_dev(const struct device *dev) @@ -305,13 +303,11 @@ iscsi_create_session(struct Scsi_Host *shost, struct iscsi_cls_session *session; int err; - if (!try_module_get(transport->owner)) - return NULL; - session = kzalloc(sizeof(*session) + transport->sessiondata_size, GFP_KERNEL); if (!session) - goto module_put; + return NULL; + session->transport = transport; session->recovery_tmo = 120; INIT_WORK(&session->recovery_work, session_recovery_timedout, session); @@ -349,8 +345,6 @@ iscsi_create_session(struct Scsi_Host *shost, free_session: kfree(session); -module_put: - module_put(transport->owner); return NULL; } -- cgit v1.2.3 From e6f3b63f50b4bb9fdc9025e0c3994acd265ad3a2 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:29 -0500 Subject: [SCSI] iscsi: rm channel usage from iscsi I do not remember what I was thinking when we added the channel as a argument to the session create function. It was probably due to too much cut and paste work from the FC transport class. The channel is meaningless for iscsi drivers so this patch drops its usage everywhere in the iscsi related code. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 2 +- drivers/scsi/scsi_transport_iscsi.c | 8 +++----- include/scsi/scsi_transport_iscsi.h | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 7e6e031cc41..499e79f0cac 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1290,7 +1290,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (!try_module_get(iscsit->owner)) goto cls_session_fail; - cls_session = iscsi_create_session(shost, iscsit, 0); + cls_session = iscsi_create_session(shost, iscsit); if (!cls_session) goto module_put; *(unsigned long*)shost->hostdata = (unsigned long)cls_session; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 8717ff51ba4..c0ec502835e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -248,10 +248,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, mutex_lock(&ihost->mutex); list_for_each_entry(session, &ihost->sessions, host_list) { - if ((channel == SCAN_WILD_CARD || - channel == session->channel) && + if ((channel == SCAN_WILD_CARD || channel == 0) && (id == SCAN_WILD_CARD || id == session->target_id)) - scsi_scan_target(&session->dev, session->channel, + scsi_scan_target(&session->dev, 0, session->target_id, lun, 1); } mutex_unlock(&ihost->mutex); @@ -297,7 +296,7 @@ EXPORT_SYMBOL_GPL(iscsi_block_session); **/ struct iscsi_cls_session * iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *transport, int channel) + struct iscsi_transport *transport) { struct iscsi_host *ihost; struct iscsi_cls_session *session; @@ -322,7 +321,6 @@ iscsi_create_session(struct Scsi_Host *shost, ihost = shost->shost_data; session->sid = iscsi_session_nr++; - session->channel = channel; session->target_id = ihost->next_target_id++; snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 05397058a9b..2e3cb37af04 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -187,7 +187,6 @@ struct iscsi_cls_session { struct work_struct recovery_work; int target_id; - int channel; int sid; /* session id */ void *dd_data; /* LLD private data */ @@ -210,7 +209,7 @@ struct iscsi_host { * session and connection functions that can be used by HW iSCSI LLDs */ extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *t, int channel); + struct iscsi_transport *t); extern int iscsi_destroy_session(struct iscsi_cls_session *session); extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, uint32_t cid); -- cgit v1.2.3 From 8434aa8b6fe5af27a33b8aa830c24e3680356c83 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:30 -0500 Subject: [SCSI] iscsi: break up session creation into two stages qla4xxx is initialized in two steps like other HW drivers. It allocates the host, sets up the HW, then adds the host. For iscsi part of HW setup is setting up persistent iscsi sessions. At that time, the interupts are off and the driver is not completely set up so we just want to allocate them. We do not want to add them to sysfs and expose them to userspace because userspace could try to do lots of fun things with them like scanning and at that time the driver is not ready. So this patch breakes up the session creation like other functions that use the driver model in two the alloc and add parts. When the driver is ready, it can then add the sessions and userspace can begin using them. This also fixes a bug in the addition error patch where we forgot to do a get on the session. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 97 ++++++++++++++++++++++++++----------- include/scsi/scsi_transport_iscsi.h | 8 +++ 2 files changed, 76 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index c0ec502835e..f39da0cf5f1 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -287,20 +287,11 @@ void iscsi_block_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_block_session); -/** - * iscsi_create_session - create iscsi class session - * @shost: scsi host - * @transport: iscsi transport - * - * This can be called from a LLD or iscsi_transport. - **/ struct iscsi_cls_session * -iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *transport) +iscsi_alloc_session(struct Scsi_Host *shost, + struct iscsi_transport *transport) { - struct iscsi_host *ihost; struct iscsi_cls_session *session; - int err; session = kzalloc(sizeof(*session) + transport->sessiondata_size, GFP_KERNEL); @@ -313,8 +304,20 @@ iscsi_create_session(struct Scsi_Host *shost, INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + session->dev.parent = &shost->shost_gendev; + session->dev.release = iscsi_session_release; + device_initialize(&session->dev); if (transport->sessiondata_size) session->dd_data = &session[1]; + return session; +} +EXPORT_SYMBOL_GPL(iscsi_alloc_session); + +int iscsi_add_session(struct iscsi_cls_session *session) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(session); + struct iscsi_host *ihost; + int err; /* this is released in the dev's release function */ scsi_host_get(shost); @@ -325,37 +328,51 @@ iscsi_create_session(struct Scsi_Host *shost, snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid); - session->dev.parent = &shost->shost_gendev; - session->dev.release = iscsi_session_release; - err = device_register(&session->dev); + err = device_add(&session->dev); if (err) { dev_printk(KERN_ERR, &session->dev, "iscsi: could not " "register session's dev\n"); - goto free_session; + goto release_host; } transport_register_device(&session->dev); mutex_lock(&ihost->mutex); list_add(&session->host_list, &ihost->sessions); mutex_unlock(&ihost->mutex); + return 0; - return session; - -free_session: - kfree(session); - return NULL; +release_host: + scsi_host_put(shost); + return err; } - -EXPORT_SYMBOL_GPL(iscsi_create_session); +EXPORT_SYMBOL_GPL(iscsi_add_session); /** - * iscsi_destroy_session - destroy iscsi session - * @session: iscsi_session + * iscsi_create_session - create iscsi class session + * @shost: scsi host + * @transport: iscsi transport * - * Can be called by a LLD or iscsi_transport. There must not be - * any running connections. + * This can be called from a LLD or iscsi_transport. **/ -int iscsi_destroy_session(struct iscsi_cls_session *session) +struct iscsi_cls_session * +iscsi_create_session(struct Scsi_Host *shost, + struct iscsi_transport *transport) +{ + struct iscsi_cls_session *session; + + session = iscsi_alloc_session(shost, transport); + if (!session) + return NULL; + + if (iscsi_add_session(session)) { + iscsi_free_session(session); + return NULL; + } + return session; +} +EXPORT_SYMBOL_GPL(iscsi_create_session); + +void iscsi_remove_session(struct iscsi_cls_session *session) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost = shost->shost_data; @@ -367,11 +384,33 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) list_del(&session->host_list); mutex_unlock(&ihost->mutex); + scsi_remove_target(&session->dev); + transport_unregister_device(&session->dev); - device_unregister(&session->dev); - return 0; + device_del(&session->dev); } +EXPORT_SYMBOL_GPL(iscsi_remove_session); +void iscsi_free_session(struct iscsi_cls_session *session) +{ + put_device(&session->dev); +} + +EXPORT_SYMBOL_GPL(iscsi_free_session); + +/** + * iscsi_destroy_session - destroy iscsi session + * @session: iscsi_session + * + * Can be called by a LLD or iscsi_transport. There must not be + * any running connections. + **/ +int iscsi_destroy_session(struct iscsi_cls_session *session) +{ + iscsi_remove_session(session); + iscsi_free_session(session); + return 0; +} EXPORT_SYMBOL_GPL(iscsi_destroy_session); static void iscsi_conn_release(struct device *dev) diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 2e3cb37af04..53493d59135 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -199,6 +199,9 @@ struct iscsi_cls_session { #define iscsi_session_to_shost(_session) \ dev_to_shost(_session->dev.parent) +#define starget_to_session(_stgt) \ + iscsi_dev_to_session(_stgt->dev.parent) + struct iscsi_host { int next_target_id; struct list_head sessions; @@ -208,8 +211,13 @@ struct iscsi_host { /* * session and connection functions that can be used by HW iSCSI LLDs */ +extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, + struct iscsi_transport *transport); +extern int iscsi_add_session(struct iscsi_cls_session *session); extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *t); +extern void iscsi_remove_session(struct iscsi_cls_session *session); +extern void iscsi_free_session(struct iscsi_cls_session *session); extern int iscsi_destroy_session(struct iscsi_cls_session *session); extern struct iscsi_cls_conn *iscsi_create_conn(struct iscsi_cls_session *sess, uint32_t cid); -- cgit v1.2.3 From 6a8a0d3621745279a131d95f0204dc9ddac60d55 Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:31 -0500 Subject: [SCSI] iscsi: pass target nr to session creation So the drivers do not use the channel numbers, but some do use the target numbers. We were just adding some goofy variable that just increases for the target nr. This is useless for software iscsi because it is always zero. And for qla4xxx the target nr is actually the index of the target/session in its FW or FLASH tables. We needed to expose this to userspace so apps could access those numbers so this patch just adds the target nr to the iscsi session creation functions. This way when qla4xxx's Hw thinks a session is at target nr 4 in its hw, it is exposed as that number in sysfs. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi.c | 2 +- drivers/scsi/scsi_transport_iscsi.c | 14 +++++++------- include/scsi/scsi_transport_iscsi.h | 7 ++++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 499e79f0cac..7e6e031cc41 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1290,7 +1290,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, if (!try_module_get(iscsit->owner)) goto cls_session_fail; - cls_session = iscsi_create_session(shost, iscsit); + cls_session = iscsi_create_session(shost, iscsit, 0); if (!cls_session) goto module_put; *(unsigned long*)shost->hostdata = (unsigned long)cls_session; diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index f39da0cf5f1..7963c0538de 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -304,6 +304,8 @@ iscsi_alloc_session(struct Scsi_Host *shost, INIT_LIST_HEAD(&session->host_list); INIT_LIST_HEAD(&session->sess_list); + /* this is released in the dev's release function */ + scsi_host_get(shost); session->dev.parent = &shost->shost_gendev; session->dev.release = iscsi_session_release; device_initialize(&session->dev); @@ -313,18 +315,15 @@ iscsi_alloc_session(struct Scsi_Host *shost, } EXPORT_SYMBOL_GPL(iscsi_alloc_session); -int iscsi_add_session(struct iscsi_cls_session *session) +int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) { struct Scsi_Host *shost = iscsi_session_to_shost(session); struct iscsi_host *ihost; int err; - /* this is released in the dev's release function */ - scsi_host_get(shost); ihost = shost->shost_data; - session->sid = iscsi_session_nr++; - session->target_id = ihost->next_target_id++; + session->target_id = target_id; snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", session->sid); @@ -356,7 +355,8 @@ EXPORT_SYMBOL_GPL(iscsi_add_session); **/ struct iscsi_cls_session * iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *transport) + struct iscsi_transport *transport, + unsigned int target_id) { struct iscsi_cls_session *session; @@ -364,7 +364,7 @@ iscsi_create_session(struct Scsi_Host *shost, if (!session) return NULL; - if (iscsi_add_session(session)) { + if (iscsi_add_session(session, target_id)) { iscsi_free_session(session); return NULL; } diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index 53493d59135..f7b0db5f2f5 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -203,7 +203,6 @@ struct iscsi_cls_session { iscsi_dev_to_session(_stgt->dev.parent) struct iscsi_host { - int next_target_id; struct list_head sessions; struct mutex mutex; }; @@ -213,9 +212,11 @@ struct iscsi_host { */ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport); -extern int iscsi_add_session(struct iscsi_cls_session *session); +extern int iscsi_add_session(struct iscsi_cls_session *session, + unsigned int target_id); extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, - struct iscsi_transport *t); + struct iscsi_transport *t, + unsigned int target_id); extern void iscsi_remove_session(struct iscsi_cls_session *session); extern void iscsi_free_session(struct iscsi_cls_session *session); extern int iscsi_destroy_session(struct iscsi_cls_session *session); -- cgit v1.2.3 From 53cb8a1f45e06a2627a6d89b151cccb95fa45cbf Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Wed, 28 Jun 2006 12:00:32 -0500 Subject: [SCSI] iscsi: add async notification of session events This patch adds or modifies the transport class functions used to notify userspace of session state events. We modify the session addition up event and add a destruction event to notify userspace of session creation, relogin and destruction. And we modify the conn error event to be sent by broadcast since multiple listeners may want to listen for it. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_iscsi.c | 309 ++++++++++++++++++++++++++---------- include/scsi/iscsi_if.h | 23 +-- include/scsi/scsi_transport_iscsi.h | 3 + 3 files changed, 235 insertions(+), 100 deletions(-) diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 7963c0538de..7b9e8fa1a4e 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -413,11 +413,59 @@ int iscsi_destroy_session(struct iscsi_cls_session *session) } EXPORT_SYMBOL_GPL(iscsi_destroy_session); +static void mempool_zone_destroy(struct mempool_zone *zp) +{ + mempool_destroy(zp->pool); + kfree(zp); +} + +static void* +mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) +{ + struct mempool_zone *zone = pool_data; + + return alloc_skb(zone->size, gfp_mask); +} + +static void +mempool_zone_free_skb(void *element, void *pool_data) +{ + kfree_skb(element); +} + +static struct mempool_zone * +mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) +{ + struct mempool_zone *zp; + + zp = kzalloc(sizeof(*zp), GFP_KERNEL); + if (!zp) + return NULL; + + zp->size = size; + zp->hiwat = hiwat; + INIT_LIST_HEAD(&zp->freequeue); + spin_lock_init(&zp->freelock); + atomic_set(&zp->allocated, 0); + + zp->pool = mempool_create(max, mempool_zone_alloc_skb, + mempool_zone_free_skb, zp); + if (!zp->pool) { + kfree(zp); + return NULL; + } + + return zp; +} + static void iscsi_conn_release(struct device *dev) { struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); struct device *parent = conn->dev.parent; + mempool_zone_destroy(conn->z_pdu); + mempool_zone_destroy(conn->z_error); + kfree(conn); put_device(parent); } @@ -427,6 +475,31 @@ static int iscsi_is_conn_dev(const struct device *dev) return dev->release == iscsi_conn_release; } +static int iscsi_create_event_pools(struct iscsi_cls_conn *conn) +{ + conn->z_pdu = mempool_zone_init(Z_MAX_PDU, + NLMSG_SPACE(sizeof(struct iscsi_uevent) + + sizeof(struct iscsi_hdr) + + DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), + Z_HIWAT_PDU); + if (!conn->z_pdu) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "pdu zone for new conn\n"); + return -ENOMEM; + } + + conn->z_error = mempool_zone_init(Z_MAX_ERROR, + NLMSG_SPACE(sizeof(struct iscsi_uevent)), + Z_HIWAT_ERROR); + if (!conn->z_error) { + dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " + "error zone for new conn\n"); + mempool_zone_destroy(conn->z_pdu); + return -ENOMEM; + } + return 0; +} + /** * iscsi_create_conn - create iscsi class connection * @session: iscsi cls session @@ -459,9 +532,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) conn->transport = transport; conn->cid = cid; + if (iscsi_create_event_pools(conn)) + goto free_conn; + /* this is released in the dev's release function */ if (!get_device(&session->dev)) - goto free_conn; + goto free_conn_pools; snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", session->sid, cid); @@ -478,6 +554,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid) release_parent_ref: put_device(&session->dev); +free_conn_pools: + free_conn: kfree(conn); return NULL; @@ -525,20 +603,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb) return (struct list_head *)&skb->cb; } -static void* -mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data) -{ - struct mempool_zone *zone = pool_data; - - return alloc_skb(zone->size, gfp_mask); -} - -static void -mempool_zone_free_skb(void *element, void *pool_data) -{ - kfree_skb(element); -} - static void mempool_zone_complete(struct mempool_zone *zone) { @@ -558,37 +622,6 @@ mempool_zone_complete(struct mempool_zone *zone) spin_unlock_irqrestore(&zone->freelock, flags); } -static struct mempool_zone * -mempool_zone_init(unsigned max, unsigned size, unsigned hiwat) -{ - struct mempool_zone *zp; - - zp = kzalloc(sizeof(*zp), GFP_KERNEL); - if (!zp) - return NULL; - - zp->size = size; - zp->hiwat = hiwat; - INIT_LIST_HEAD(&zp->freequeue); - spin_lock_init(&zp->freelock); - atomic_set(&zp->allocated, 0); - - zp->pool = mempool_create(max, mempool_zone_alloc_skb, - mempool_zone_free_skb, zp); - if (!zp->pool) { - kfree(zp); - return NULL; - } - - return zp; -} - -static void mempool_zone_destroy(struct mempool_zone *zp) -{ - mempool_destroy(zp->pool); - kfree(zp); -} - static struct sk_buff* mempool_zone_get_skb(struct mempool_zone *zone) { @@ -600,6 +633,27 @@ mempool_zone_get_skb(struct mempool_zone *zone) return skb; } +static int +iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb) +{ + unsigned long flags; + int rc; + + skb_get(skb); + rc = netlink_broadcast(nls, skb, 0, 1, GFP_KERNEL); + if (rc < 0) { + mempool_free(skb, zone->pool); + printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc); + return rc; + } + + spin_lock_irqsave(&zone->freelock, flags); + INIT_LIST_HEAD(skb_to_lh(skb)); + list_add(skb_to_lh(skb), &zone->freequeue); + spin_unlock_irqrestore(&zone->freelock, flags); + return 0; +} + static int iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid) { @@ -695,7 +749,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error) ev->r.connerror.cid = conn->cid; ev->r.connerror.sid = iscsi_conn_get_sid(conn); - iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid); + iscsi_broadcast_skb(conn->z_error, skb); dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n", error); @@ -796,6 +850,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) return err; } +/** + * iscsi_if_destroy_session_done - send session destr. completion event + * @conn: last connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * removed a session. + **/ +int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_KEVENT_DESTROY_SESSION; + ev->r.d_session.host_no = shost->host_no; + ev->r.d_session.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session destruction event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_del(&session->sess_list); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + conn->active = 0; + list_del(&conn->conn_list); + spin_unlock_irqrestore(&connlock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done); + +/** + * iscsi_if_create_session_done - send session creation completion event + * @conn: leading connection for session + * + * This is called by HW iscsi LLDs to notify userpsace that its HW has + * created a session or a existing session is back in the logged in state. + **/ +int iscsi_if_create_session_done(struct iscsi_cls_conn *conn) +{ + struct iscsi_internal *priv; + struct iscsi_cls_session *session; + struct Scsi_Host *shost; + struct iscsi_uevent *ev; + struct sk_buff *skb; + struct nlmsghdr *nlh; + unsigned long flags; + int rc, len = NLMSG_SPACE(sizeof(*ev)); + + priv = iscsi_if_transport_lookup(conn->transport); + if (!priv) + return -EINVAL; + + session = iscsi_dev_to_session(conn->dev.parent); + shost = iscsi_session_to_shost(session); + + mempool_zone_complete(conn->z_pdu); + + skb = mempool_zone_get_skb(conn->z_pdu); + if (!skb) { + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event\n"); + return -ENOMEM; + } + + nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0); + ev = NLMSG_DATA(nlh); + ev->transport_handle = iscsi_handle(conn->transport); + ev->type = ISCSI_UEVENT_CREATE_SESSION; + ev->r.c_session_ret.host_no = shost->host_no; + ev->r.c_session_ret.sid = session->sid; + + /* + * this will occur if the daemon is not up, so we just warn + * the user and when the daemon is restarted it will handle it + */ + rc = iscsi_broadcast_skb(conn->z_pdu, skb); + if (rc < 0) + dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of " + "session creation event. Check iscsi daemon\n"); + + spin_lock_irqsave(&sesslock, flags); + list_add(&session->sess_list, &sesslist); + spin_unlock_irqrestore(&sesslock, flags); + + spin_lock_irqsave(&connlock, flags); + list_add(&conn->conn_list, &connlist); + conn->active = 1; + spin_unlock_irqrestore(&connlock, flags); + return rc; +} +EXPORT_SYMBOL_GPL(iscsi_if_create_session_done); + static int iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev) { @@ -841,26 +1020,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) return -ENOMEM; } - conn->z_pdu = mempool_zone_init(Z_MAX_PDU, - NLMSG_SPACE(sizeof(struct iscsi_uevent) + - sizeof(struct iscsi_hdr) + - DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH), - Z_HIWAT_PDU); - if (!conn->z_pdu) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "pdu zone for new conn\n"); - goto destroy_conn; - } - - conn->z_error = mempool_zone_init(Z_MAX_ERROR, - NLMSG_SPACE(sizeof(struct iscsi_uevent)), - Z_HIWAT_ERROR); - if (!conn->z_error) { - dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate " - "error zone for new conn\n"); - goto free_pdu_pool; - } - ev->r.c_conn_ret.sid = session->sid; ev->r.c_conn_ret.cid = conn->cid; @@ -870,13 +1029,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) spin_unlock_irqrestore(&connlock, flags); return 0; - -free_pdu_pool: - mempool_zone_destroy(conn->z_pdu); -destroy_conn: - if (transport->destroy_conn) - transport->destroy_conn(conn->dd_data); - return -ENOMEM; } static int @@ -884,7 +1036,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev { unsigned long flags; struct iscsi_cls_conn *conn; - struct mempool_zone *z_error, *z_pdu; conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); if (!conn) @@ -894,15 +1045,8 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev list_del(&conn->conn_list); spin_unlock_irqrestore(&connlock, flags); - z_pdu = conn->z_pdu; - z_error = conn->z_error; - if (transport->destroy_conn) transport->destroy_conn(conn); - - mempool_zone_destroy(z_pdu); - mempool_zone_destroy(z_error); - return 0; } @@ -1331,6 +1475,7 @@ iscsi_register_transport(struct iscsi_transport *tt) if (!priv) return NULL; INIT_LIST_HEAD(&priv->list); + priv->daemon_pid = -1; priv->iscsi_transport = tt; priv->t.user_scan = iscsi_user_scan; diff --git a/include/scsi/iscsi_if.h b/include/scsi/iscsi_if.h index 8813f0f4c62..55ebf035e62 100644 --- a/include/scsi/iscsi_if.h +++ b/include/scsi/iscsi_if.h @@ -53,6 +53,7 @@ enum iscsi_uevent_e { ISCSI_KEVENT_RECV_PDU = KEVENT_BASE + 1, ISCSI_KEVENT_CONN_ERROR = KEVENT_BASE + 2, ISCSI_KEVENT_IF_ERROR = KEVENT_BASE + 3, + ISCSI_KEVENT_DESTROY_SESSION = KEVENT_BASE + 4, }; enum iscsi_tgt_dscvr { @@ -157,27 +158,13 @@ struct iscsi_uevent { uint32_t cid; uint32_t error; /* enum iscsi_err */ } connerror; + struct msg_session_destroyed { + uint32_t host_no; + uint32_t sid; + } d_session; struct msg_transport_connect_ret { uint64_t handle; } ep_connect_ret; - struct msg_tgt_dscvr_ret { - /* - * session/connection pair used to reference - * the connection to server - */ - uint32_t sid; - uint32_t cid; - union { - struct isns { - /* port # for conn to iSNS server */ - uint16_t isns_port; - /* listening port to receive SCNs */ - uint16_t scn_port; - /* listening port to receive ESIs */ - uint16_t esi_port; - } isns_attrib; - } u; - } tgt_dscvr_ret; } r; } __attribute__ ((aligned (sizeof(uint64_t)))); diff --git a/include/scsi/scsi_transport_iscsi.h b/include/scsi/scsi_transport_iscsi.h index f7b0db5f2f5..5a3df1d7085 100644 --- a/include/scsi/scsi_transport_iscsi.h +++ b/include/scsi/scsi_transport_iscsi.h @@ -214,6 +214,8 @@ extern struct iscsi_cls_session *iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport); extern int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id); +extern int iscsi_if_create_session_done(struct iscsi_cls_conn *conn); +extern int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn); extern struct iscsi_cls_session *iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *t, unsigned int target_id); @@ -226,4 +228,5 @@ extern int iscsi_destroy_conn(struct iscsi_cls_conn *conn); extern void iscsi_unblock_session(struct iscsi_cls_session *session); extern void iscsi_block_session(struct iscsi_cls_session *session); + #endif -- cgit v1.2.3 From 0f13fc09db68de92585558984bff1c51b87db72f Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 29 Jun 2006 13:02:11 -0400 Subject: [SCSI] 53c700: fix breakage caused by the autosense update A bit of a brown paper bag issue. The previous patch to remove the soon to be ripped out fields that were used in autosense actually broke the driver. This patch fixes it and has been tested (honestly). Signed-off-by: James Bottomley --- drivers/scsi/53c700.c | 56 +++++++++++++++++++++++++++------------------------ drivers/scsi/53c700.h | 34 +++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c index bff04797739..24dfd54865e 100644 --- a/drivers/scsi/53c700.c +++ b/drivers/scsi/53c700.c @@ -174,6 +174,7 @@ STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt); STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); +STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth); @@ -183,10 +184,6 @@ STATIC struct device_attribute *NCR_700_dev_attrs[]; STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; -struct NCR_700_sense { - unsigned char cmnd[MAX_COMMAND_SIZE]; -}; - static char *NCR_700_phase[] = { "", "after selection", @@ -334,6 +331,7 @@ NCR_700_detect(struct scsi_host_template *tpnt, tpnt->use_clustering = ENABLE_CLUSTERING; tpnt->slave_configure = NCR_700_slave_configure; tpnt->slave_destroy = NCR_700_slave_destroy; + tpnt->slave_alloc = NCR_700_slave_alloc; tpnt->change_queue_depth = NCR_700_change_queue_depth; tpnt->change_queue_type = NCR_700_change_queue_type; @@ -612,9 +610,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - NCR_700_unmap(hostdata, SCp, slot); + dma_unmap_single(hostdata->dev, slot->pCmd, + sizeof(SCp->cmnd), DMA_TO_DEVICE); if (slot->flags == NCR_700_FLAG_AUTOSENSE) { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_700_DEBUG printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", SCp, SCp->cmnd[7], result); @@ -625,10 +624,9 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, /* restore the old result if the request sense was * successful */ if(result == 0) - result = sense->cmnd[7]; + result = cmnd[7]; } else - dma_unmap_single(hostdata->dev, slot->pCmd, - sizeof(SCp->cmnd), DMA_TO_DEVICE); + NCR_700_unmap(hostdata, SCp, slot); free_slot(slot, hostdata); #ifdef NCR_700_DEBUG @@ -970,14 +968,15 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { struct NCR_700_command_slot *slot = (struct NCR_700_command_slot *)SCp->host_scribble; - if(SCp->cmnd[0] == REQUEST_SENSE) { + if(slot->flags == NCR_700_FLAG_AUTOSENSE) { /* OOPS: bad device, returning another * contingent allegiance condition */ scmd_printk(KERN_ERR, SCp, "broken device is looping in contingent allegiance: ignoring\n"); NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); } else { - struct NCR_700_sense *sense = SCp->device->hostdata; + char *cmnd = + NCR_700_get_sense_cmnd(SCp->device); #ifdef NCR_DEBUG scsi_print_command(SCp); printk(" cmd %p has status %d, requesting sense\n", @@ -995,21 +994,21 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, sizeof(SCp->cmnd), DMA_TO_DEVICE); - sense->cmnd[0] = REQUEST_SENSE; - sense->cmnd[1] = (SCp->device->lun & 0x7) << 5; - sense->cmnd[2] = 0; - sense->cmnd[3] = 0; - sense->cmnd[4] = sizeof(SCp->sense_buffer); - sense->cmnd[5] = 0; + cmnd[0] = REQUEST_SENSE; + cmnd[1] = (SCp->device->lun & 0x7) << 5; + cmnd[2] = 0; + cmnd[3] = 0; + cmnd[4] = sizeof(SCp->sense_buffer); + cmnd[5] = 0; /* Here's a quiet hack: the * REQUEST_SENSE command is six bytes, * so store a flag indicating that * this was an internal sense request * and the original status at the end * of the command */ - sense->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; - sense->cmnd[7] = hostdata->status[0]; - slot->pCmd = dma_map_single(hostdata->dev, sense->cmnd, sizeof(sense->cmnd), DMA_TO_DEVICE); + cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; + cmnd[7] = hostdata->status[0]; + slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE); slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer)); slot->SG[0].pAddr = bS_to_host(slot->dma_handle); @@ -1531,7 +1530,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs) /* clear all the negotiated parameters */ __shost_for_each_device(SDp, host) - SDp->hostdata = NULL; + NCR_700_clear_flag(SDp, ~0); /* clear all the slots and their pending commands */ for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { @@ -2036,7 +2035,17 @@ NCR_700_set_offset(struct scsi_target *STp, int offset) spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; } +STATIC int +NCR_700_slave_alloc(struct scsi_device *SDp) +{ + SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), + GFP_KERNEL); + if (!SDp->hostdata) + return -ENOMEM; + + return 0; +} STATIC int NCR_700_slave_configure(struct scsi_device *SDp) @@ -2044,11 +2053,6 @@ NCR_700_slave_configure(struct scsi_device *SDp) struct NCR_700_Host_Parameters *hostdata = (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - SDp->hostdata = kmalloc(sizeof(struct NCR_700_sense), GFP_KERNEL); - - if (!SDp->hostdata) - return -ENOMEM; - /* to do here: allocate memory; build a queue_full list */ if(SDp->tagged_supported) { scsi_set_tag_type(SDp, MSG_ORDERED_TAG); diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h index 7f22a06fe5e..97ebe71b701 100644 --- a/drivers/scsi/53c700.h +++ b/drivers/scsi/53c700.h @@ -12,7 +12,7 @@ #include #include - +#include /* Turn on for general debugging---too verbose for normal use */ #undef NCR_700_DEBUG @@ -76,11 +76,16 @@ struct NCR_700_SG_List { #define SCRIPT_RETURN 0x90080000 }; -/* We use device->hostdata to store negotiated parameters. This is - * supposed to be a pointer to a device private area, but we cannot - * really use it as such since it will never be freed, so just use the - * 32 bits to cram the information. The SYNC negotiation sequence looks - * like: +struct NCR_700_Device_Parameters { + /* space for creating a request sense command. Really, except + * for the annoying SCSI-2 requirement for LUN information in + * cmnd[1], this could be in static storage */ + unsigned char cmnd[MAX_COMMAND_SIZE]; + __u8 depth; +}; + + +/* The SYNC negotiation sequence looks like: * * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION @@ -98,19 +103,26 @@ struct NCR_700_SG_List { #define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) #define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) +static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp) +{ + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->cmnd; +} + static inline void NCR_700_set_depth(struct scsi_device *SDp, __u8 depth) { - long l = (long)SDp->hostdata; + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - l &= 0xffff00ff; - l |= 0xff00 & (depth << 8); - SDp->hostdata = (void *)l; + hostdata->depth = depth; } static inline __u8 NCR_700_get_depth(struct scsi_device *SDp) { - return ((((unsigned long)SDp->hostdata) & 0xff00)>>8); + struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; + + return hostdata->depth; } static inline int NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag) -- cgit v1.2.3 From 454e8957eb60841016deb319dbbf83042fb32a39 Mon Sep 17 00:00:00 2001 From: Ishai Rabinovitz Date: Thu, 29 Jun 2006 16:39:54 +0300 Subject: [SCSI] sg.c: Fix bad error handling in I got a NULL derefrence in cdev_del+1 when called from sg_remove. By looking at the code of sg_add, sg_alloc and sg_remove (all in drivers/scsi/sg.c) I found out that sg_add is calling sg_alloc but if it fails afterwards it does not deallocate the space that was allocated in sg_alloc and the redundant entry has NULL in cdev. When sg_remove is being called, it tries to perform cdev_del to this NULL cdev and fails. Signed-off-by: Ishai Rabinovitz Acked-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 98b9312ba8d..d5bbb97bb74 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1402,6 +1402,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) Sg_device *sdp = NULL; struct cdev * cdev = NULL; int error, k; + unsigned long iflags; disk = alloc_disk(1); if (!disk) { @@ -1429,7 +1430,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); if (error) - goto out; + goto cdev_add_err; sdp->cdev = cdev; if (sg_sysfs_valid) { @@ -1456,6 +1457,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) return 0; +cdev_add_err: + write_lock_irqsave(&sg_dev_arr_lock, iflags); + kfree(sg_dev_arr[k]); + sg_dev_arr[k] = NULL; + sg_nr_dev--; + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + out: put_disk(disk); if (cdev) -- cgit v1.2.3 From 376ac8307868f93a0b9aa277f43dee0f63c41c1b Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Thu, 29 Jun 2006 17:36:26 -0600 Subject: [SCSI] mptsas: make two functions static Make two needlessly global functions static. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptsas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index bc36f5fdb53..85eff1509d6 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -337,7 +337,7 @@ mptsas_is_end_device(struct mptsas_devinfo * attached) } /* no mutex */ -void +static void mptsas_port_delete(struct mptsas_portinfo_details * port_details) { struct mptsas_portinfo *port_info; @@ -438,7 +438,7 @@ starget) * Updates for new and existing narrow/wide port configuration * in the sas_topology */ -void +static void mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) { struct mptsas_portinfo_details * port_details; -- cgit v1.2.3 From 3e00a5b28782d65b7ac91e1e9812c281c2ec7af0 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Thu, 29 Jun 2006 17:38:43 -0600 Subject: [SCSI] mptbase: mpt_interrupt should return IRQ_NONE The way mpt_interrupt() was coded, it was impossible for the unhandled interrupt detection logic to ever trigger. All interrupt handlers should return IRQ_NONE when they have nothing to do. Signed-off-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Eric Moore Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 8ac77caf933..20609966c2a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -369,20 +369,21 @@ static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) { MPT_ADAPTER *ioc = bus_id; - u32 pa; + u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + + if (pa == 0xFFFFFFFF) + return IRQ_NONE; /* * Drain the reply FIFO! */ - while (1) { - pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); - if (pa == 0xFFFFFFFF) - return IRQ_HANDLED; - else if (pa & MPI_ADDRESS_REPLY_A_BIT) + do { + if (pa & MPI_ADDRESS_REPLY_A_BIT) mpt_reply(ioc, pa); else mpt_turbo_reply(ioc, pa); - } + pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + } while (pa != 0xFFFFFFFF); return IRQ_HANDLED; } -- cgit v1.2.3 From 900d9f98737b502fbd0303cfcab2773b465bb1f8 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Fri, 30 Jun 2006 02:33:07 -0700 Subject: [SCSI] small whitespace cleanup for qlogic driver Add a few spaces to MODULE_PARM_DESC() text for qla2xxx. Without these spaces text runs together when modinfo prints the text. Signed-off-by: Jesper Juhl Acked-by: Andrew Vasquez Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3516e36107b..01fc30c49ad 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -39,14 +39,14 @@ MODULE_PARM_DESC(ql2xlogintimeout, int qlport_down_retry = 30; module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(qlport_down_retry, - "Maximum number of command retries to a port that returns" + "Maximum number of command retries to a port that returns " "a PORT-DOWN status."); int ql2xplogiabsentdevice; module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xplogiabsentdevice, "Option to enable PLOGI to devices that are not present after " - "a Fabric scan. This is needed for several broken switches." + "a Fabric scan. This is needed for several broken switches. " "Default is 0 - no PLOGI. 1 - perfom PLOGI."); int ql2xloginretrycount = 0; -- cgit v1.2.3 From 413975a0f1a43a896490fc5c589d05c95624c6d2 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 30 Jun 2006 02:33:06 -0700 Subject: [SCSI] qla2xxx: make some more functions static Make some needlessly global functions static. Signed-off-by: Adrian Bunk Acked-by: Andrew Vasquez Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 6 ------ drivers/scsi/qla2xxx/qla_init.c | 8 +++++--- drivers/scsi/qla2xxx/qla_iocb.c | 3 ++- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 750aef11c2e..8311ac2b93a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -31,13 +31,9 @@ extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *); - -extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t); extern int qla2x00_loop_resync(scsi_qla_host_t *); -extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); @@ -84,8 +80,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *); /* * Global Function Prototypes in qla_iocb.c source file. */ -extern void qla2x00_isp_cmd(scsi_qla_host_t *); - extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_64(uint16_t); extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ce74a6025a0..9758dba9554 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -39,6 +39,8 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, static int qla2x00_restart_isp(scsi_qla_host_t *); +static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev); + /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -1790,7 +1792,7 @@ qla2x00_rport_del(void *data) * * Returns a pointer to the allocated fcport, or NULL, if none available. */ -fc_port_t * +static fc_port_t * qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags) { fc_port_t *fcport; @@ -2586,7 +2588,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) * Context: * Kernel context. */ -int +static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev) { int rval; @@ -3561,7 +3563,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha) return (rval); } -int +static int qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr) { int rval; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 8c769cfaa14..2b60a27eff0 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -15,6 +15,7 @@ static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd); static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *); static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *); static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha); +static void qla2x00_isp_cmd(scsi_qla_host_t *ha); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. @@ -574,7 +575,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha) * * Note: The caller must hold the hardware lock before calling this routine. */ -void +static void qla2x00_isp_cmd(scsi_qla_host_t *ha) { device_reg_t __iomem *reg = ha->iobase; -- cgit v1.2.3 From 2686de27a356914e098329463d5a8cd7aa6f29a4 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 30 Jun 2006 12:54:02 -0500 Subject: [SCSI] mptsas: eliminate ghost devices One of the current problems the mptsas driver has is that of "ghost" devices (these are devices the firmware reports as existing, but what they actually represent are the parents of a lower device), so for example in my dual expander configuration, three expanders actually show up, two for the real expanders but a third is created because the firmware reports that the lower expander also has another expander connected (which is simply the port going back to the upper expander). The attached patch eliminates all these ghosts by not allocating any devices for them if the SAS address is the SAS address of the parent. Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.h | 1 + drivers/message/fusion/mptsas.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 7bf0855f934..2697b70653f 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -632,6 +632,7 @@ typedef struct _MPT_ADAPTER struct mutex sas_discovery_mutex; u8 sas_discovery_runtime; u8 sas_discovery_ignore_events; + u16 handle; int sas_index; /* index refrencing */ MPT_SAS_MGMT sas_mgmt; int num_ports; diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 85eff1509d6..f7bd8b11ed3 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -1635,8 +1635,10 @@ static int mptsas_probe_one_phy(struct device *dev, if (!mptsas_get_rphy(phy_info) && port && !port->rphy) { struct sas_rphy *rphy; + struct device *parent; struct sas_identify identify; + parent = dev->parent->parent; /* * Let the hotplug_work thread handle processing * the adding/removing of devices that occur @@ -1647,6 +1649,27 @@ static int mptsas_probe_one_phy(struct device *dev, goto out; mptsas_parse_device_info(&identify, &phy_info->attached); + if (scsi_is_host_device(parent)) { + struct mptsas_portinfo *port_info; + int i; + + mutex_lock(&ioc->sas_topology_mutex); + port_info = mptsas_find_portinfo_by_handle(ioc, + ioc->handle); + mutex_unlock(&ioc->sas_topology_mutex); + + for (i = 0; i < port_info->num_phys; i++) + if (port_info->phy_info[i].identify.sas_address == + identify.sas_address) + goto out; + + } else if (scsi_is_sas_rphy(parent)) { + struct sas_rphy *parent_rphy = dev_to_rphy(parent); + if (identify.sas_address == + parent_rphy->identify.sas_address) + goto out; + } + switch (identify.device_type) { case SAS_END_DEVICE: rphy = sas_end_device_alloc(port); @@ -1698,6 +1721,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc) goto out_free_port_info; mutex_lock(&ioc->sas_topology_mutex); + ioc->handle = hba->handle; port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); if (!port_info) { port_info = hba; -- cgit v1.2.3 From f58f8313a6f552d1e7889926a29f0cf91c02f55d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 30 Jun 2006 02:33:14 -0700 Subject: [SCSI] qla1280: fix section mismatch warnings Fix section mismatch warnings: WARNING: drivers/scsi/qla1280.o - Section mismatch: reference to .init.data: from .text between 'qla1280_get_token' (at offset 0x2a16) and 'qla1280_probe_one' WARNING: drivers/scsi/qla1280.o - Section mismatch: reference to .init.data: from .text between 'qla1280_get_token' (at offset 0x2a3c) and 'qla1280_probe_one' Signed-off-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 680f6063954..f09d54058ce 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4210,7 +4210,7 @@ qla1280_setup(char *s) } -static int +static int __init qla1280_get_token(char *str) { char *sep; -- cgit v1.2.3 From d6b0c53723753fc0cfda63f56735b225c43e1e9a Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 2 Jul 2006 10:06:28 -0500 Subject: [SCSI] fix error handling in scsi_io_completion There was a logic fault in scsi_io_completion() where zero transfer commands that complete successfully were sent to the block layer as not up to date. This patch removes the if (good_bytes > 0) gate around the successful completion, since zero transfer commands do have good_bytes == 0. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bf5191f6aaa..08af9aae7df 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -920,22 +920,20 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) * Next deal with any sectors which we were able to correctly * handle. */ - if (good_bytes > 0) { - SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " - "%d bytes done.\n", - req->nr_sectors, good_bytes)); - SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); - - if (clear_errors) - req->errors = 0; - - /* A number of bytes were successfully read. If there - * is leftovers and there is some kind of error - * (result != 0), retry the rest. - */ - if (scsi_end_request(cmd, 1, good_bytes, !!result) == NULL) - return; - } + SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, " + "%d bytes done.\n", + req->nr_sectors, good_bytes)); + SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg)); + + if (clear_errors) + req->errors = 0; + + /* A number of bytes were successfully read. If there + * are leftovers and there is some kind of error + * (result != 0), retry the rest. + */ + if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL) + return; /* good_bytes = 0, or (inclusive) there were leftovers and * result = 0, so scsi_end_request couldn't retry. -- cgit v1.2.3