From 0a637a2cec724eeb4649f6d1c07026b72c39ad84 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 19 Jul 2005 22:04:24 +0200 Subject: [SCSI] aic byteorder fixes after recent cleanup aic doesnt work anymore after this change which appeared int 2.6.13-rc1: [SCSI] aic7xxx/aic79xx: remove useless byte order macro cruft 2 files did not include byteorder.h, aic died with panic "Unknown opcode encountered in seq program" This patch fixes it for me. Signed-off-by: Olaf Hering Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aicasm/aicasm.c | 4 ++-- drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c index c3463948190..f936b691232 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c @@ -369,7 +369,7 @@ output_code() fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], @@ -613,7 +613,7 @@ output_listing(char *ifilename) line++; } fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h index 3e80f07df49..e64f802bbaa 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h @@ -42,8 +42,10 @@ * $FreeBSD$ */ +#include + struct ins_format1 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t immediate : 8, source : 9, destination : 9, @@ -61,7 +63,7 @@ struct ins_format1 { }; struct ins_format2 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t shift_control : 8, source : 9, destination : 9, @@ -79,7 +81,7 @@ struct ins_format2 { }; struct ins_format3 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t immediate : 8, source : 9, address : 10, -- cgit v1.2.3 From 5dbffcd83d826a9b42a10afb89b13156dc5b9539 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 27 Jul 2005 01:07:42 -0700 Subject: [SCSI] git-scsi-misc: drivers/scsi/ch.c: remove devfs stuff It seems very unlikely that this driver will go into any stable kernel before devfs will be removed. Signed-off-by: Adrian Bunk Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 3900e28ac7d..53b39553431 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include /* here are all the ioctls */ @@ -940,8 +939,6 @@ static int ch_probe(struct device *dev) if (init) ch_init_elem(ch); - devfs_mk_cdev(MKDEV(SCSI_CHANGER_MAJOR,ch->minor), - S_IFCHR | S_IRUGO | S_IWUGO, ch->name); class_device_create(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor), dev, "s%s", ch->name); @@ -974,7 +971,6 @@ static int ch_remove(struct device *dev) class_device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); - devfs_remove(ch->name); kfree(ch->dt); kfree(ch); ch_devcount--; -- cgit v1.2.3 From d3301874083874f8a0ac88aa1bb7da6b62df34d2 Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:12:38 -0700 Subject: [SCSI] host state model update: replace old host bitmap state Migrate the current SCSI host state model to a model like SCSI device is using. Signed-off-by: Mike Anderson Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 88 +++++++++++++++++++++++++++++++++++++++++++---- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_error.c | 7 ++-- drivers/scsi/scsi_ioctl.c | 3 +- drivers/scsi/scsi_lib.c | 4 +-- drivers/scsi/scsi_sysfs.c | 62 +++++++++++++++++++++++++++++++++ drivers/scsi/sg.c | 3 +- 7 files changed, 153 insertions(+), 16 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 5feb886c339..6828ca305c2 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -51,6 +51,82 @@ static struct class shost_class = { .release = scsi_host_cls_release, }; +/** + * scsi_host_set_state - Take the given host through the host + * state model. + * @shost: scsi host to change the state of. + * @state: state to change to. + * + * Returns zero if unsuccessful or an error if the requested + * transition is illegal. + **/ +int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) +{ + enum scsi_host_state oldstate = shost->shost_state; + + if (state == oldstate) + return 0; + + switch (state) { + case SHOST_CREATED: + /* There are no legal states that come back to + * created. This is the manually initialised start + * state */ + goto illegal; + + case SHOST_RUNNING: + switch (oldstate) { + case SHOST_CREATED: + case SHOST_RECOVERY: + break; + default: + goto illegal; + } + break; + + case SHOST_RECOVERY: + switch (oldstate) { + case SHOST_RUNNING: + break; + default: + goto illegal; + } + break; + + case SHOST_CANCEL: + switch (oldstate) { + case SHOST_CREATED: + case SHOST_RUNNING: + break; + default: + goto illegal; + } + break; + + case SHOST_DEL: + switch (oldstate) { + case SHOST_CANCEL: + break; + default: + goto illegal; + } + break; + + } + shost->shost_state = state; + return 0; + + illegal: + SCSI_LOG_ERROR_RECOVERY(1, + dev_printk(KERN_ERR, &shost->shost_gendev, + "Illegal host state transition" + "%s->%s\n", + scsi_host_state_name(oldstate), + scsi_host_state_name(state))); + return -EINVAL; +} +EXPORT_SYMBOL(scsi_host_set_state); + /** * scsi_host_cancel - cancel outstanding IO to this host * @shost: pointer to struct Scsi_Host @@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) { struct scsi_device *sdev; - set_bit(SHOST_CANCEL, &shost->shost_state); + scsi_host_set_state(shost, SHOST_CANCEL); shost_for_each_device(sdev, shost) { scsi_device_cancel(sdev, recovery); } - wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, - &shost->shost_state))); + wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY)); } /** @@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *shost) scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); - set_bit(SHOST_DEL, &shost->shost_state); + scsi_host_set_state(shost, SHOST_DEL); transport_unregister_device(&shost->shost_gendev); class_device_unregister(&shost->shost_classdev); @@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) if (error) goto out; - set_bit(SHOST_ADD, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RUNNING); get_device(shost->shost_gendev.parent); error = class_device_add(&shost->shost_classdev); @@ -226,6 +301,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) spin_lock_init(&shost->default_lock); scsi_assign_lock(shost, &shost->default_lock); + shost->shost_state = SHOST_CREATED; INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__targets); INIT_LIST_HEAD(&shost->eh_cmd_q); @@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup); **/ struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) { - if (test_bit(SHOST_DEL, &shost->shost_state) || + if ((shost->shost_state == SHOST_DEL) || !get_device(&shost->shost_gendev)) return NULL; return shost; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d14523d7e44..fb85b3ced7b 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) spin_lock_irqsave(host->host_lock, flags); scsi_cmd_get_serial(host, cmd); - if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) { + if (unlikely(host->shost_state == SHOST_CANCEL)) { cmd->result = (DID_NO_CONNECT << 16); scsi_done(cmd); } else { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 0fc8b48f052..e9c451ba71f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -75,7 +75,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) scmd->eh_eflags |= eh_flag; list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); - set_bit(SHOST_RECOVERY, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RECOVERY); shost->host_failed++; scsi_eh_wakeup(shost); spin_unlock_irqrestore(shost->host_lock, flags); @@ -197,7 +197,8 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) { int online; - wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->shost_state))); + wait_event(sdev->host->host_wait, (sdev->host->shost_state != + SHOST_RECOVERY)); online = scsi_device_online(sdev); @@ -1458,7 +1459,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost) SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", __FUNCTION__)); - clear_bit(SHOST_RECOVERY, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RUNNING); wake_up(&shost->host_wait); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 7a6b530115a..f5bf5c07be9 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -475,8 +475,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, * error processing, as long as the device was opened * non-blocking */ if (filp && filp->f_flags & O_NONBLOCK) { - if (test_bit(SHOST_RECOVERY, - &sdev->host->shost_state)) + if (sdev->host->shost_state == SHOST_RECOVERY) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7a91ca3d32a..060010bccab 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -348,7 +348,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); shost->host_busy--; - if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) && + if (unlikely((shost->shost_state == SHOST_RECOVERY) && shost->host_failed)) scsi_eh_wakeup(shost); spin_unlock(shost->host_lock); @@ -1207,7 +1207,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q, struct Scsi_Host *shost, struct scsi_device *sdev) { - if (test_bit(SHOST_RECOVERY, &shost->shost_state)) + if (shost->shost_state == SHOST_RECOVERY) return 0; if (shost->host_busy == 0 && shost->host_blocked) { /* diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index beed7fbe1cb..dae59d1da07 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -48,6 +48,30 @@ const char *scsi_device_state_name(enum scsi_device_state state) return name; } +static struct { + enum scsi_host_state value; + char *name; +} shost_states[] = { + { SHOST_CREATED, "created" }, + { SHOST_RUNNING, "running" }, + { SHOST_CANCEL, "cancel" }, + { SHOST_DEL, "deleted" }, + { SHOST_RECOVERY, "recovery" }, +}; +const char *scsi_host_state_name(enum scsi_host_state state) +{ + int i; + char *name = NULL; + + for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) { + if (shost_states[i].value == state) { + name = shost_states[i].name; + break; + } + } + return name; +} + static int check_set(unsigned int *val, char *src) { char *last; @@ -124,6 +148,43 @@ static ssize_t store_scan(struct class_device *class_dev, const char *buf, }; static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); +static ssize_t +store_shost_state(struct class_device *class_dev, const char *buf, size_t count) +{ + int i; + struct Scsi_Host *shost = class_to_shost(class_dev); + enum scsi_host_state state = 0; + + for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) { + const int len = strlen(shost_states[i].name); + if (strncmp(shost_states[i].name, buf, len) == 0 && + buf[len] == '\n') { + state = shost_states[i].value; + break; + } + } + if (!state) + return -EINVAL; + + if (scsi_host_set_state(shost, state)) + return -EINVAL; + return count; +} + +static ssize_t +show_shost_state(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + const char *name = scsi_host_state_name(shost->shost_state); + + if (!name) + return -EINVAL; + + return snprintf(buf, 20, "%s\n", name); +} + +static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); + shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); @@ -139,6 +200,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unchecked_isa_dma, &class_device_attr_proc_name, &class_device_attr_scan, + &class_device_attr_state, NULL }; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 51292f269ce..14fb179b384 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (sdp->detached) return -ENODEV; if (filp->f_flags & O_NONBLOCK) { - if (test_bit(SHOST_RECOVERY, - &sdp->device->host->shost_state)) + if (sdp->device->host->shost_state == SHOST_RECOVERY) return -EBUSY; } else if (!scsi_block_when_processing_errors(sdp->device)) return -EBUSY; -- cgit v1.2.3 From d2c9d9eafa03dbd08a8a439e6c5addb8b1f03b9b Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:13:42 -0700 Subject: [SCSI] host state model update: reimplement scsi_host_cancel Remove the old scsi_host_cancel function as it has not been working for sometime do to the device list possibly being empty when it is called and possible race issues. Add setting of SHOST_CANCEL at the state of beginning of scsi_remove_host. Signed-off-by: Mike Anderson Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 18 +----------------- drivers/scsi/scsi.c | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 6828ca305c2..67c4c0c3aa5 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -127,30 +127,14 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) } EXPORT_SYMBOL(scsi_host_set_state); -/** - * scsi_host_cancel - cancel outstanding IO to this host - * @shost: pointer to struct Scsi_Host - * recovery: recovery requested to run. - **/ -static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) -{ - struct scsi_device *sdev; - - scsi_host_set_state(shost, SHOST_CANCEL); - shost_for_each_device(sdev, shost) { - scsi_device_cancel(sdev, recovery); - } - wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY)); -} - /** * scsi_remove_host - remove a scsi host * @shost: a pointer to a scsi host to remove **/ void scsi_remove_host(struct Scsi_Host *shost) { + scsi_host_set_state(shost, SHOST_CANCEL); scsi_forget_host(shost); - scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); scsi_host_set_state(shost, SHOST_DEL); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index fb85b3ced7b..d1aa95d45a7 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) spin_lock_irqsave(host->host_lock, flags); scsi_cmd_get_serial(host, cmd); - if (unlikely(host->shost_state == SHOST_CANCEL)) { + if (unlikely(host->shost_state == SHOST_DEL)) { cmd->result = (DID_NO_CONNECT << 16); scsi_done(cmd); } else { -- cgit v1.2.3 From 82f29467a025f6a2192d281e97fca0be46e905cc Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:14:33 -0700 Subject: [SCSI] host state model update: mediate host add/remove race Add support to not allow additions to a host when it is being removed. Signed-off-by: Mike Anderson Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 2 ++ drivers/scsi/scsi_scan.c | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 67c4c0c3aa5..8640ad1c17e 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -133,7 +133,9 @@ EXPORT_SYMBOL(scsi_host_set_state); **/ void scsi_remove_host(struct Scsi_Host *shost) { + down(&shost->scan_mutex); scsi_host_set_state(shost, SHOST_CANCEL); + up(&shost->scan_mutex); scsi_forget_host(shost); scsi_proc_host_rm(shost); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 2d3c4ac475f..076cbe3b5a0 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1251,9 +1251,12 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, get_device(&starget->dev); down(&shost->scan_mutex); - res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); - if (res != SCSI_SCAN_LUN_PRESENT) - sdev = ERR_PTR(-ENODEV); + if (scsi_host_scan_allowed(shost)) { + res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, + hostdata); + if (res != SCSI_SCAN_LUN_PRESENT) + sdev = ERR_PTR(-ENODEV); + } up(&shost->scan_mutex); scsi_target_reap(starget); put_device(&starget->dev); @@ -1403,11 +1406,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, return -EINVAL; down(&shost->scan_mutex); - if (channel == SCAN_WILD_CARD) - for (channel = 0; channel <= shost->max_channel; channel++) + if (scsi_host_scan_allowed(shost)) { + if (channel == SCAN_WILD_CARD) + for (channel = 0; channel <= shost->max_channel; + channel++) + scsi_scan_channel(shost, channel, id, lun, + rescan); + else scsi_scan_channel(shost, channel, id, lun, rescan); - else - scsi_scan_channel(shost, channel, id, lun, rescan); + } up(&shost->scan_mutex); return 0; -- cgit v1.2.3 From a6c42741ace2fee235b6902e76f3c86a01d32146 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:13 +0200 Subject: [SCSI] qla1280: remove dead per-host flag variables Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 7 ------- drivers/scsi/qla1280.h | 4 ---- 2 files changed, 11 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index b993652bfa2..eb5543ef513 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -996,7 +996,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) break; case ABORT_DEVICE: - ha->flags.in_reset = 1; if (qla1280_verbose) printk(KERN_INFO "scsi(%ld:%d:%d:%d): Queueing abort device " @@ -1010,7 +1009,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) printk(KERN_INFO "scsi(%ld:%d:%d:%d): Queueing device reset " "command.\n", ha->host_no, bus, target, lun); - ha->flags.in_reset = 1; if (qla1280_device_reset(ha, bus, target) == 0) result = SUCCESS; break; @@ -1019,7 +1017,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) if (qla1280_verbose) printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS " "DEVICE RESET\n", ha->host_no, bus); - ha->flags.in_reset = 1; if (qla1280_bus_reset(ha, bus == 0)) result = SUCCESS; @@ -1047,7 +1044,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) if (!list_empty(&ha->done_q)) qla1280_done(ha); - ha->flags.in_reset = 0; /* If we didn't manage to issue the action, or we have no * command to wait for, exit here */ @@ -1636,7 +1632,6 @@ qla1280_enable_intrs(struct scsi_qla_host *ha) /* enable risc and host interrupts */ WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 1; } static inline void @@ -1648,7 +1643,6 @@ qla1280_disable_intrs(struct scsi_qla_host *ha) /* disable risc and host interrupts */ WRT_REG_WORD(®->ictrl, 0); RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 0; } /* @@ -1679,7 +1673,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) ha->flags.reset_active = 0; ha->flags.abort_isp_active = 0; - ha->flags.ints_enabled = 0; #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) if (ia64_platform_is("sn2")) { printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index d245ae07518..1c1cf3a5af0 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1082,10 +1082,6 @@ struct scsi_qla_host { uint32_t reset_active:1; /* 3 */ uint32_t abort_isp_active:1; /* 4 */ uint32_t disable_risc_code_load:1; /* 5 */ - uint32_t enable_64bit_addressing:1; /* 6 */ - uint32_t in_reset:1; /* 7 */ - uint32_t ints_enabled:1; - uint32_t ignore_nvram:1; #ifdef __ia64__ uint32_t use_pci_vchannel:1; #endif -- cgit v1.2.3 From 8af50dcd22aa0a5840f18276ff10a6977abc3853 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:19 +0200 Subject: [SCSI] qla1280: interupt posting for irq disabling/enabling Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 57 ++++++++++++++++++-------------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index eb5543ef513..58ecdc69667 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1265,6 +1265,22 @@ qla1280_biosparam_old(Disk * disk, kdev_t dev, int geom[]) return qla1280_biosparam(disk->device, NULL, disk->capacity, geom); } #endif + +/* disable risc and host interrupts */ +static inline void +qla1280_disable_intrs(struct scsi_qla_host *ha) +{ + WRT_REG_WORD(&ha->iobase->ictrl, 0); + RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ +} + +/* enable risc and host interrupts */ +static inline void +qla1280_enable_intrs(struct scsi_qla_host *ha) +{ + WRT_REG_WORD(&ha->iobase->ictrl, (ISP_EN_INT | ISP_EN_RISC)); + RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ +} /************************************************************************** * qla1280_intr_handler @@ -1286,7 +1302,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) ha->isr_count++; reg = ha->iobase; - WRT_REG_WORD(®->ictrl, 0); /* disable our interrupt. */ + qla1280_disable_intrs(ha); data = qla1280_debounce_register(®->istatus); /* Check for pending interrupts. */ @@ -1299,8 +1315,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(HOST_LOCK); - /* enable our interrupt. */ - WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); + qla1280_enable_intrs(ha); LEAVE_INTR("qla1280_intr_handler"); return IRQ_RETVAL(handled); @@ -1613,38 +1628,6 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) /* QLogic ISP1280 Hardware Support Functions. */ /****************************************************************************/ - /* - * qla2100_enable_intrs - * qla2100_disable_intrs - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * None - */ -static inline void -qla1280_enable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg; - - reg = ha->iobase; - /* enable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ -} - -static inline void -qla1280_disable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg; - - reg = ha->iobase; - /* disable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, 0); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ -} - /* * qla1280_initialize_adapter * Initialize board. @@ -4751,7 +4734,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #if LINUX_VERSION_CODE >= 0x020600 error_disable_adapter: - WRT_REG_WORD(&ha->iobase->ictrl, 0); + qla1280_disable_intrs(ha); #endif error_free_irq: free_irq(pdev->irq, ha); @@ -4788,7 +4771,7 @@ qla1280_remove_one(struct pci_dev *pdev) scsi_remove_host(host); #endif - WRT_REG_WORD(&ha->iobase->ictrl, 0); + qla1280_disable_intrs(ha); free_irq(pdev->irq, ha); -- cgit v1.2.3 From 2b55cac3d2d9f545c141748d00eae86e2c042ca5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:30 +0200 Subject: [SCSI] qla1280: misc cleanups print message tidy ups and some excess brace removal. Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 58ecdc69667..e5354550d76 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1459,7 +1459,6 @@ qla1280_select_queue_depth(struct Scsi_Host *host, struct scsi_device *sdev_q) * * Input: * ha = adapter block pointer. - * done_q = done queue. */ static void qla1280_done(struct scsi_qla_host *ha) @@ -1593,7 +1592,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) case CS_DATA_OVERRUN: dprintk(2, "Data overrun 0x%x\n", residual_length); - dprintk(2, "qla1280_isr: response packet data\n"); + dprintk(2, "qla1280_return_status: response packet data\n"); qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE); host_status = DID_ERROR; break; @@ -2061,7 +2060,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); if (err) { - printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no); + printk(KERN_ERR "scsi(%li): RISC checksum failed.\n", ha->host_no); return err; } @@ -3080,10 +3079,13 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); } + dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n", + ha->req_q_cnt, seg_cnt); + /* If room for request in request ring. */ if ((req_cnt + 2) >= ha->req_q_cnt) { status = 1; - dprintk(2, "qla1280_64bit_start_scsi: in-ptr=0x%x req_q_cnt=" + dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt=" "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, req_cnt); goto out; @@ -3095,7 +3097,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) if (cnt >= MAX_OUTSTANDING_COMMANDS) { status = 1; - dprintk(2, "qla1280_64bit_start_scsi: NO ROOM IN " + dprintk(2, "qla1280_start_scsi: NO ROOM IN " "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt); goto out; } @@ -3104,7 +3106,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) ha->req_q_cnt -= req_cnt; CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)(cnt + 1); - dprintk(2, "64bit_start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, + dprintk(2, "start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd)); dprintk(2, " bus %i, target %i, lun %i\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); @@ -4626,7 +4628,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) { if (pci_set_dma_mask(ha->pdev, 0xffffffff)) { printk(KERN_WARNING "scsi(%li): Unable to set a " - " suitable DMA mask - aboring\n", ha->host_no); + "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; goto error_free_irq; } @@ -4636,14 +4638,14 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #else if (pci_set_dma_mask(ha->pdev, 0xffffffff)) { printk(KERN_WARNING "scsi(%li): Unable to set a " - " suitable DMA mask - aboring\n", ha->host_no); + "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; goto error_free_irq; } #endif ha->request_ring = pci_alloc_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), &ha->request_dma); if (!ha->request_ring) { printk(KERN_INFO "qla1280: Failed to get request memory\n"); @@ -4651,7 +4653,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } ha->response_ring = pci_alloc_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), &ha->response_dma); if (!ha->response_ring) { printk(KERN_INFO "qla1280: Failed to get response memory\n"); @@ -4746,11 +4748,11 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #endif error_free_response_ring: pci_free_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), ha->response_ring, ha->response_dma); error_free_request_ring: pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), ha->request_ring, ha->request_dma); error_put_host: scsi_host_put(host); -- cgit v1.2.3 From d6db3e8d5fe3178776d0a0314e612c3f55e55fb4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:36 +0200 Subject: [SCSI] qla1280: use SAM_ constants Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qla1280.h | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index e5354550d76..3732230b2e3 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4049,7 +4049,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, /* Save ISP completion status */ CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd); - if (scsi_status & SS_CHECK_CONDITION) { + if (scsi_status & SAM_STAT_CHECK_CONDITION) { if (comp_status != CS_ARS_FAILED) { uint16_t req_sense_length = le16_to_cpu(pkt->req_sense_length); diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 1c1cf3a5af0..0d430d63be4 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -978,14 +978,6 @@ struct ctio_a64_ret_entry { #define CS_UNKNOWN 0x81 /* Driver defined */ #define CS_RETRY 0x82 /* Driver defined */ -/* - * ISP status entry - SCSI status byte bit definitions. - */ -#define SS_CHECK_CONDITION BIT_1 -#define SS_CONDITION_MET BIT_2 -#define SS_BUSY_CONDITION BIT_3 -#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) - /* * ISP target entries - Option flags bit definitions. */ -- cgit v1.2.3 From 748422d92a55faadf3184e5aa8487da88c1ee849 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:41 +0200 Subject: [SCSI] qla1280: remove SG_SEGMENTS Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 0d430d63be4..18c20cf371a 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -94,9 +94,6 @@ #define REQUEST_ENTRY_CNT 256 /* Number of request entries. */ #define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */ -/* Number of segments 1 - 65535 */ -#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ - /* * SCSI Request Block structure (sp) that is placed * on cmd->SCp location of every I/O -- cgit v1.2.3 From 5c79d6154f335543ea4c4a555f645a1f76b5d117 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:46 +0200 Subject: [SCSI] qla1280: always load microcode we have the most recent microcode, make sure to always load it. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 72 +------------------------------------------------- 1 file changed, 1 insertion(+), 71 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 3732230b2e3..9f975f7c1ea 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1733,69 +1733,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) return status; } - -/* - * ISP Firmware Test - * Checks if present version of RISC firmware is older than - * driver firmware. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = firmware does not need to be loaded. - */ -static int -qla1280_isp_firmware(struct scsi_qla_host *ha) -{ - struct nvram *nv = (struct nvram *) ha->response_ring; - int status = 0; /* dg 2/27 always loads RISC */ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - - ENTER("qla1280_isp_firmware"); - - dprintk(1, "scsi(%li): Determining if RISC is loaded\n", ha->host_no); - - /* Bad NVRAM data, load RISC code. */ - if (!ha->nvram_valid) { - ha->flags.disable_risc_code_load = 0; - } else - ha->flags.disable_risc_code_load = - nv->cntr_flags_1.disable_loading_risc_code; - - if (ha->flags.disable_risc_code_load) { - dprintk(3, "qla1280_isp_firmware: Telling RISC to verify " - "checksum of loaded BIOS code.\n"); - - /* Verify checksum of loaded RISC code. */ - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - - if (!(status = - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { - /* Start firmware execution. */ - dprintk(3, "qla1280_isp_firmware: Startng F/W " - "execution.\n"); - - mb[0] = MBC_EXECUTE_FIRMWARE; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - } else - printk(KERN_INFO "qla1280: RISC checksum failed.\n"); - } else { - dprintk(1, "qla1280: NVRAM configured to load RISC load.\n"); - status = 1; - } - - if (status) - dprintk(2, "qla1280_isp_firmware: **** Load RISC code ****\n"); - - LEAVE("qla1280_isp_firmware"); - return status; -} - /* * Chip diagnostics * Test chip for proper operation. @@ -2080,14 +2017,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) static int qla1280_load_firmware(struct scsi_qla_host *ha) { - int err = -ENODEV; - - /* If firmware needs to be loaded */ - if (!qla1280_isp_firmware(ha)) { - printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", - ha->host_no); - goto out; - } + int err; err = qla1280_chip_diag(ha); if (err) -- cgit v1.2.3 From 0888f4c3312847eec4814a6d7cdcaaaa9fbd3345 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:55 +0200 Subject: [SCSI] qla1280: don't use bitfields for hardware access in isp_config Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 44 +++++++++++++++++++++++++++++--------------- drivers/scsi/qla1280.h | 30 ++++++++++++------------------ 2 files changed, 41 insertions(+), 33 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 9f975f7c1ea..1a8b1147821 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2189,9 +2189,9 @@ qla1280_set_defaults(struct scsi_qla_host *ha) /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ nv->firmware_feature.f.enable_fast_posting = 1; nv->firmware_feature.f.disable_synchronous_backoff = 1; - nv->termination.f.scsi_bus_0_control = 3; - nv->termination.f.scsi_bus_1_control = 3; - nv->termination.f.auto_term_support = 1; + nv->termination.scsi_bus_0_control = 3; + nv->termination.scsi_bus_1_control = 3; + nv->termination.auto_term_support = 1; /* * Set default FIFO magic - What appropriate values would be here @@ -2201,7 +2201,12 @@ qla1280_set_defaults(struct scsi_qla_host *ha) * header file provided by QLogic seems to be bogus or incomplete * at best. */ - nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128; + nv->isp_config.burst_enable = 1; + if (IS_ISP1040(ha)) + nv->isp_config.fifo_threshold |= 3; + else + nv->isp_config.fifo_threshold |= 4; + if (IS_ISP1x160(ha)) nv->isp_parameter = 0x01; /* fast memory enable */ @@ -2362,31 +2367,40 @@ qla1280_nvram_config(struct scsi_qla_host *ha) hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; - cfg1 = RD_REG_WORD(®->cfg_1); + cfg1 = RD_REG_WORD(®->cfg_1) & ~(BIT_4 | BIT_5 | BIT_6); cdma_conf = RD_REG_WORD(®->cdma_cfg); ddma_conf = RD_REG_WORD(®->ddma_cfg); /* Busted fifo, says mjacob. */ - if (hwrev == ISP_CFG0_1040A) - WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64); - else - WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB); + if (hwrev != ISP_CFG0_1040A) + cfg1 |= nv->isp_config.fifo_threshold << 4; + + cfg1 |= nv->isp_config.burst_enable << 2; + WRT_REG_WORD(®->cfg_1, cfg1); WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); } else { + uint16_t cfg1, term; + /* Set ISP hardware DMA burst */ - mb[0] = nv->isp_config.c; + cfg1 = nv->isp_config.fifo_threshold << 4; + cfg1 |= nv->isp_config.burst_enable << 2; /* Enable DMA arbitration on dual channel controllers */ if (ha->ports > 1) - mb[0] |= BIT_13; - WRT_REG_WORD(®->cfg_1, mb[0]); + cfg1 |= BIT_13; + WRT_REG_WORD(®->cfg_1, cfg1); /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); - mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); - WRT_REG_WORD(®->gpio_data, mb[0]); + WRT_REG_WORD(®->gpio_enable, + BIT_7 | BIT_3 | BIT_2 | BIT_1 | BIT_0); + term = nv->termination.scsi_bus_1_control; + term |= nv->termination.scsi_bus_0_control << 2; + term |= nv->termination.auto_term_support << 7; + RD_REG_WORD(®->id_l); /* Flush PCI write */ + WRT_REG_WORD(®->gpio_data, term); } + RD_REG_WORD(®->id_l); /* Flush PCI write */ /* ISP parameter word. */ mb[0] = MBC_SET_SYSTEM_PARAMETER; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 18c20cf371a..4032ea3f2b9 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -375,29 +375,23 @@ struct nvram { uint16_t unused_12; /* 12, 13 */ uint16_t unused_14; /* 14, 15 */ - union { - uint8_t c; - struct { - uint8_t reserved:2; - uint8_t burst_enable:1; - uint8_t reserved_1:1; - uint8_t fifo_threshold:4; - } f; + struct { + uint8_t reserved:2; + uint8_t burst_enable:1; + uint8_t reserved_1:1; + uint8_t fifo_threshold:4; } isp_config; /* 16 */ /* Termination * 0 = Disable, 1 = high only, 3 = Auto term */ - union { - uint8_t c; - struct { - uint8_t scsi_bus_1_control:2; - uint8_t scsi_bus_0_control:2; - uint8_t unused_0:1; - uint8_t unused_1:1; - uint8_t unused_2:1; - uint8_t auto_term_support:1; - } f; + struct { + uint8_t scsi_bus_1_control:2; + uint8_t scsi_bus_0_control:2; + uint8_t unused_0:1; + uint8_t unused_1:1; + uint8_t unused_2:1; + uint8_t auto_term_support:1; } termination; /* 17 */ uint16_t isp_parameter; /* 18, 19 */ -- cgit v1.2.3 From 7a34766fdcec0c619aa68ace203b934dd7cf9dbc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:49:22 +0200 Subject: [SCSI] qla1280: don't use bitfields for hardware access, parameters Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 143 +++++++++++++++++++++++++------------------------ drivers/scsi/qla1280.h | 21 ++++---- 2 files changed, 81 insertions(+), 83 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 1a8b1147821..6481deb5704 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1328,7 +1328,7 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; - int status; + int status, lun; nv = &ha->nvram; @@ -1336,24 +1336,38 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) /* Set Target Parameters. */ mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - - mb[2] = (nv->bus[bus].target[target].parameter.c << 8); + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[2] = nv->bus[bus].target[target].parameter.renegotiate_on_error << 8; + mb[2] |= nv->bus[bus].target[target].parameter.stop_queue_on_check << 9; + mb[2] |= nv->bus[bus].target[target].parameter.auto_request_sense << 10; + mb[2] |= nv->bus[bus].target[target].parameter.tag_queuing << 11; + mb[2] |= nv->bus[bus].target[target].parameter.enable_sync << 12; + mb[2] |= nv->bus[bus].target[target].parameter.enable_wide << 13; + mb[2] |= nv->bus[bus].target[target].parameter.parity_checking << 14; + mb[2] |= nv->bus[bus].target[target].parameter.disconnect_allowed << 15; if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | - nv->bus[bus].target[target].sync_period; + mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8); mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; } else { - mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | - nv->bus[bus].target[target].sync_period; + mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8); } + mb[3] |= nv->bus[bus].target[target].sync_period; + + status = qla1280_mailbox_command(ha, mr, mb); - status = qla1280_mailbox_command(ha, mr, &mb[0]); + /* Set Device Queue Parameters. */ + for (lun = 0; lun < MAX_LUNS; lun++) { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[1] |= lun; + mb[2] = nv->bus[bus].max_queue_depth; + mb[3] = nv->bus[bus].target[target].execution_throttle; + status |= qla1280_mailbox_command(ha, 0x0f, mb); + } if (status) printk(KERN_WARNING "scsi(%ld:%i:%i): " @@ -1400,19 +1414,19 @@ qla1280_slave_configure(struct scsi_device *device) } #if LINUX_VERSION_CODE > 0x020500 - nv->bus[bus].target[target].parameter.f.enable_sync = device->sdtr; - nv->bus[bus].target[target].parameter.f.enable_wide = device->wdtr; + nv->bus[bus].target[target].parameter.enable_sync = device->sdtr; + nv->bus[bus].target[target].parameter.enable_wide = device->wdtr; nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr; #endif if (driver_setup.no_sync || (driver_setup.sync_mask && (~driver_setup.sync_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.f.enable_sync = 0; + nv->bus[bus].target[target].parameter.enable_sync = 0; if (driver_setup.no_wide || (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.f.enable_wide = 0; + nv->bus[bus].target[target].parameter.enable_wide = 0; if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && @@ -1421,7 +1435,7 @@ qla1280_slave_configure(struct scsi_device *device) } spin_lock_irqsave(HOST_LOCK, flags); - if (nv->bus[bus].target[target].parameter.f.enable_sync) + if (nv->bus[bus].target[target].parameter.enable_sync) status = qla1280_set_target_parameters(ha, bus, target); qla1280_get_target_parameters(ha, device); spin_unlock_irqrestore(HOST_LOCK, flags); @@ -2151,17 +2165,17 @@ qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) { struct nvram *nv = &ha->nvram; - nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.f.auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f.tag_queuing = 1; - nv->bus[bus].target[target].parameter.f.enable_sync = 1; + nv->bus[bus].target[target].parameter.renegotiate_on_error = 1; + nv->bus[bus].target[target].parameter.auto_request_sense = 1; + nv->bus[bus].target[target].parameter.tag_queuing = 1; + nv->bus[bus].target[target].parameter.enable_sync = 1; #if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.f.enable_wide = 1; + nv->bus[bus].target[target].parameter.enable_wide = 1; #endif - nv->bus[bus].target[target].parameter.f.parity_checking = 1; - nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1; nv->bus[bus].target[target].execution_throttle = nv->bus[bus].max_queue_depth - 1; + nv->bus[bus].target[target].parameter.parity_checking = 1; + nv->bus[bus].target[target].parameter.disconnect_allowed = 1; if (IS_ISP1x160(ha)) { nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; @@ -2237,66 +2251,53 @@ qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) struct nvram *nv = &ha->nvram; uint16_t mb[MAILBOX_REGISTER_COUNT]; int status, lun; + uint16_t flag; /* Set Target Parameters. */ mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - - /* - * Do not enable wide, sync, and ppr for the initial - * INQUIRY run. We enable this later if we determine - * the target actually supports it. - */ - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - stop_queue_on_check = 0; - - if (IS_ISP1x160(ha)) - nv->bus[bus].target[target].ppr_1x160. - flags.enable_ppr = 0; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); /* - * No sync, wide, etc. while probing + * Do not enable sync and ppr for the initial INQUIRY run. We + * enable this later if we determine the target actually + * supports it. */ - mb[2] = (nv->bus[bus].target[target].parameter.c << 8) & - ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); + mb[2] = (TP_RENEGOTIATE | TP_AUTO_REQUEST_SENSE | TP_TAGGED_QUEUE + | TP_WIDE | TP_PARITY | TP_DISCONNECT); if (IS_ISP1x160(ha)) mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; else mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; mb[3] |= nv->bus[bus].target[target].sync_period; - - status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); + status = qla1280_mailbox_command(ha, 0x0f, mb); /* Save Tag queuing enable flag. */ - mb[0] = BIT_0 << target; - if (nv->bus[bus].target[target].parameter.f.tag_queuing) - ha->bus_settings[bus].qtag_enables |= mb[0]; + flag = (BIT_0 << target) & mb[0]; + if (nv->bus[bus].target[target].parameter.tag_queuing) + ha->bus_settings[bus].qtag_enables |= flag; /* Save Device enable flag. */ if (IS_ISP1x160(ha)) { if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].device_enables |= flag; ha->bus_settings[bus].lun_disables |= 0; } else { if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].device_enables |= flag; /* Save LUN disable flag. */ if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= mb[0]; + ha->bus_settings[bus].lun_disables |= flag; } /* Set Device Queue Parameters. */ for (lun = 0; lun < MAX_LUNS; lun++) { mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)(bus ? target | BIT_7 : target); - mb[1] = mb[1] << 8 | lun; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[1] |= lun; mb[2] = nv->bus[bus].max_queue_depth; mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]); + status |= qla1280_mailbox_command(ha, 0x0f, mb); } return status; @@ -2341,7 +2342,6 @@ qla1280_nvram_config(struct scsi_qla_host *ha) struct nvram *nv = &ha->nvram; int bus, target, status = 0; uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t mask; ENTER("qla1280_nvram_config"); @@ -2349,7 +2349,7 @@ qla1280_nvram_config(struct scsi_qla_host *ha) /* Always force AUTO sense for LINUX SCSI */ for (bus = 0; bus < MAX_BUSES; bus++) for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. + nv->bus[bus].target[target].parameter. auto_request_sense = 1; } } else { @@ -2416,16 +2416,17 @@ qla1280_nvram_config(struct scsi_qla_host *ha) /* Firmware feature word. */ mb[0] = MBC_SET_FIRMWARE_FEATURES; - mask = BIT_5 | BIT_1 | BIT_0; - mb[1] = le16_to_cpu(nv->firmware_feature.w) & (mask); + mb[1] = nv->firmware_feature.f.enable_fast_posting; + mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1; + mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5; #if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2) if (ia64_platform_is("sn2")) { printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " "workaround\n", ha->host_no); - mb[1] |= BIT_9; + mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */ } #endif - status |= qla1280_mailbox_command(ha, mask, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* Retry count and delay. */ mb[0] = MBC_SET_RETRY_COUNT; @@ -2454,27 +2455,27 @@ qla1280_nvram_config(struct scsi_qla_host *ha) mb[2] |= BIT_5; if (nv->bus[1].config_2.data_line_active_negation) mb[2] |= BIT_4; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); mb[0] = MBC_SET_DATA_OVERRUN_RECOVERY; mb[1] = 2; /* Reset SCSI bus and return all outstanding IO */ - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* thingy */ mb[0] = MBC_SET_PCI_CONTROL; - mb[1] = 2; /* Data DMA Channel Burst Enable */ - mb[2] = 2; /* Command DMA Channel Burst Enable */ - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + mb[1] = BIT_1; /* Data DMA Channel Burst Enable */ + mb[2] = BIT_1; /* Command DMA Channel Burst Enable */ + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); mb[0] = MBC_SET_TAG_AGE_LIMIT; mb[1] = 8; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* Selection timeout. */ mb[0] = MBC_SET_SELECTION_TIMEOUT; mb[1] = nv->bus[0].selection_timeout; mb[2] = nv->bus[1].selection_timeout; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); for (bus = 0; bus < ha->ports; bus++) status |= qla1280_config_bus(ha, bus); @@ -3915,21 +3916,21 @@ qla1280_get_target_options(struct scsi_cmnd *cmd, struct scsi_qla_host *ha) result = cmd->request_buffer; n = &ha->nvram; - n->bus[bus].target[target].parameter.f.enable_wide = 0; - n->bus[bus].target[target].parameter.f.enable_sync = 0; + n->bus[bus].target[target].parameter.enable_wide = 0; + n->bus[bus].target[target].parameter.enable_sync = 0; n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0; if (result[7] & 0x60) - n->bus[bus].target[target].parameter.f.enable_wide = 1; + n->bus[bus].target[target].parameter.enable_wide = 1; if (result[7] & 0x10) - n->bus[bus].target[target].parameter.f.enable_sync = 1; + n->bus[bus].target[target].parameter.enable_sync = 1; if ((result[2] >= 3) && (result[4] + 5 > 56) && (result[56] & 0x4)) n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; dprintk(2, "get_target_options(): wide %i, sync %i, ppr %i\n", - n->bus[bus].target[target].parameter.f.enable_wide, - n->bus[bus].target[target].parameter.f.enable_sync, + n->bus[bus].target[target].parameter.enable_wide, + n->bus[bus].target[target].parameter.enable_sync, n->bus[bus].target[target].ppr_1x160.flags.enable_ppr); } #endif diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 4032ea3f2b9..7c919db97a4 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -451,18 +451,15 @@ struct nvram { uint16_t unused_38; /* 38, 39 */ struct { - union { - uint8_t c; - struct { - uint8_t renegotiate_on_error:1; - uint8_t stop_queue_on_check:1; - uint8_t auto_request_sense:1; - uint8_t tag_queuing:1; - uint8_t enable_sync:1; - uint8_t enable_wide:1; - uint8_t parity_checking:1; - uint8_t disconnect_allowed:1; - } f; + struct { + uint8_t renegotiate_on_error:1; + uint8_t stop_queue_on_check:1; + uint8_t auto_request_sense:1; + uint8_t tag_queuing:1; + uint8_t enable_sync:1; + uint8_t enable_wide:1; + uint8_t parity_checking:1; + uint8_t disconnect_allowed:1; } parameter; /* 40 */ uint8_t execution_throttle; /* 41 */ -- cgit v1.2.3 From 8d6810d33e5e43b11675190318a81303c601a568 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:49:26 +0200 Subject: [SCSI] qla1280: endianess annotations Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 8 +- drivers/scsi/qla1280.h | 270 ++++++++++++++++++++++++------------------------- 2 files changed, 139 insertions(+), 139 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6481deb5704..637fb6565d2 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1546,7 +1546,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) int host_status = DID_ERROR; uint16_t comp_status = le16_to_cpu(sts->comp_status); uint16_t state_flags = le16_to_cpu(sts->state_flags); - uint16_t residual_length = le16_to_cpu(sts->residual_length); + uint16_t residual_length = le32_to_cpu(sts->residual_length); uint16_t scsi_status = le16_to_cpu(sts->scsi_status); #if DEBUG_QLA1280_INTR static char *reason[] = { @@ -1932,7 +1932,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) "%d,%d(0x%x)\n", risc_code_address, cnt, num, risc_address); for(i = 0; i < cnt; i++) - ((uint16_t *)ha->request_ring)[i] = + ((__le16 *)ha->request_ring)[i] = cpu_to_le16(risc_code_address[i]); mb[0] = MBC_LOAD_RAM; @@ -2986,7 +2986,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct scsi_cmnd *cmd = sp->cmd; cmd_a64_entry_t *pkt; struct scatterlist *sg = NULL; - u32 *dword_ptr; + __le32 *dword_ptr; dma_addr_t dma_handle; int status = 0; int cnt; @@ -3273,7 +3273,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; struct scatterlist *sg = NULL; - uint32_t *dword_ptr; + __le32 *dword_ptr; int status = 0; int cnt; int req_cnt; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 7c919db97a4..59915fb7030 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -516,23 +516,23 @@ struct cmd_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ + __le32 handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ }; /* @@ -544,21 +544,21 @@ struct cont_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t reserved; /* Reserved */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ - uint32_t dseg_5_address; /* Data segment 5 address. */ - uint32_t dseg_5_length; /* Data segment 5 length. */ - uint32_t dseg_6_address; /* Data segment 6 address. */ - uint32_t dseg_6_length; /* Data segment 6 length. */ + __le32 reserved; /* Reserved */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_4_address; /* Data segment 4 address. */ + __le32 dseg_4_length; /* Data segment 4 length. */ + __le32 dseg_5_address; /* Data segment 5 address. */ + __le32 dseg_5_length; /* Data segment 5 length. */ + __le32 dseg_6_address; /* Data segment 6 address. */ + __le32 dseg_6_length; /* Data segment 6 length. */ }; /* @@ -574,22 +574,22 @@ struct response { #define RF_FULL BIT_1 /* Full */ #define RF_BAD_HEADER BIT_2 /* Bad header. */ #define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */ - uint32_t handle; /* System handle. */ - uint16_t scsi_status; /* SCSI status. */ - uint16_t comp_status; /* Completion status. */ - uint16_t state_flags; /* State flags. */ -#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ -#define SF_GOT_SENSE BIT_13 /* Got Sense */ -#define SF_GOT_STATUS BIT_12 /* Got Status */ -#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ -#define SF_SENT_CDB BIT_10 /* Send CDB */ -#define SF_GOT_TARGET BIT_9 /* */ -#define SF_GOT_BUS BIT_8 /* */ - uint16_t status_flags; /* Status flags. */ - uint16_t time; /* Time. */ - uint16_t req_sense_length; /* Request sense data length. */ - uint32_t residual_length; /* Residual transfer length. */ - uint16_t reserved[4]; + __le32 handle; /* System handle. */ + __le16 scsi_status; /* SCSI status. */ + __le16 comp_status; /* Completion status. */ + __le16 state_flags; /* State flags. */ +#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ +#define SF_GOT_SENSE BIT_13 /* Got Sense */ +#define SF_GOT_STATUS BIT_12 /* Got Status */ +#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ +#define SF_SENT_CDB BIT_10 /* Send CDB */ +#define SF_GOT_TARGET BIT_9 /* */ +#define SF_GOT_BUS BIT_8 /* */ + __le16 status_flags; /* Status flags. */ + __le16 time; /* Time. */ + __le16 req_sense_length;/* Request sense data length. */ + __le32 residual_length; /* Residual transfer length. */ + __le16 reserved[4]; uint8_t req_sense_data[32]; /* Request sense data. */ }; @@ -602,7 +602,7 @@ struct mrk_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t reserved; + __le32 reserved; uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ uint8_t modifier; /* Modifier (7-0). */ @@ -626,11 +626,11 @@ struct ecmd_entry { uint32_t handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[88]; /* SCSI command words. */ }; @@ -643,20 +643,20 @@ typedef struct { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ + __le32 handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t reserved_1[2]; /* unused */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ + __le32 reserved_1[2]; /* unused */ + __le32 dseg_0_address[2]; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2]; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ } cmd_a64_entry_t, request_t; /* @@ -668,16 +668,16 @@ struct cont_a64_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address[2]; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address[2]; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address[2]; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ + __le32 dseg_0_address[2]; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2]; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address[2]; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address[2]; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_4_address[2]; /* Data segment 4 address. */ + __le32 dseg_4_length; /* Data segment 4 length. */ }; /* @@ -689,10 +689,10 @@ struct elun_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status not used. */ - uint32_t reserved_2; - uint16_t lun; /* Bit 15 is bus number. */ - uint16_t reserved_4; - uint32_t option_flags; + __le32 reserved_2; + __le16 lun; /* Bit 15 is bus number. */ + __le16 reserved_4; + __le32 option_flags; uint8_t status; uint8_t reserved_5; uint8_t command_count; /* Number of ATIOs allocated. */ @@ -702,8 +702,8 @@ struct elun_entry { /* commands (2-26). */ uint8_t group_7_length; /* SCSI CDB length for group 7 */ /* commands (2-26). */ - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t reserved_6[20]; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 reserved_6[20]; }; /* @@ -717,20 +717,20 @@ struct modify_lun_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t reserved_3; uint8_t operators; uint8_t reserved_4; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t reserved_5; uint8_t command_count; /* Number of ATIOs allocated. */ uint8_t immed_notify_count; /* Number of Immediate Notify */ /* entries allocated. */ - uint16_t reserved_6; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t reserved_7[20]; + __le16 reserved_6; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 reserved_7[20]; }; /* @@ -742,20 +742,20 @@ struct notify_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t reserved_4; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ /* entries allocated. */ - uint16_t seq_id; + __le16 seq_id; uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */ - uint16_t reserved_5[8]; + __le16 reserved_5[8]; uint8_t sense_data[18]; }; @@ -768,16 +768,16 @@ struct nack_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t event; - uint16_t seq_id; - uint16_t reserved_4[22]; + __le16 seq_id; + __le16 reserved_4[22]; }; /* @@ -789,12 +789,12 @@ struct atio_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t cdb_len; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ @@ -812,28 +812,28 @@ struct ctio_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ }; /* @@ -845,24 +845,24 @@ struct ctio_ret_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint16_t dseg_1_length; /* Data segment 1 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le16 dseg_1_length; /* Data segment 1 length. */ uint8_t sense_data[18]; }; @@ -875,25 +875,25 @@ struct ctio_a64_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t reserved_4[2]; - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 reserved_4[2]; + __le32 dseg_0_address[2];/* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2];/* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ }; /* @@ -905,21 +905,21 @@ struct ctio_a64_ret_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint16_t reserved_4[7]; + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le16 reserved_4[7]; uint8_t sense_data[18]; }; -- cgit v1.2.3 From 60a13213840296b1e32d6781653a0eaa83d04382 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 22 Jul 2005 16:42:28 +0200 Subject: [SCSI] aic79xx: Remove busyq From: Jeff Garzik This patch removes the busyq in aic79xx and uses the command-queue from the midlayer instead. Additionally some dead code is removed. Signed-off-by: Hannes Reinecke Fixed rejections Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_core.c | 1 - drivers/scsi/aic7xxx/aic79xx_osm.c | 824 ++++++------------------------------ drivers/scsi/aic7xxx/aic79xx_osm.h | 26 +- drivers/scsi/aic7xxx/aic79xx_proc.c | 12 - 4 files changed, 139 insertions(+), 724 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 137fb1a37dd..d69bbffb34a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -9039,7 +9039,6 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); } printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); - ahd_platform_dump_card_state(ahd); ahd_restore_modes(ahd, saved_modes); if (paused == 0) ahd_unpause(ahd); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 329cb233133..7463dd515d1 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -53,11 +53,6 @@ #include "aiclib.c" #include /* __setup */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "sd.h" /* For geometry detection */ -#endif - #include /* For fetching system memory size */ #include /* For ssleep/msleep */ @@ -66,11 +61,6 @@ */ spinlock_t ahd_list_spinlock; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* For dynamic sglist size calculation. */ -u_int ahd_linux_nseg; -#endif - /* * Bucket size for counting good commands in between bad ones. */ @@ -457,7 +447,6 @@ static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, static void ahd_linux_dev_timed_unfreeze(u_long arg); static void ahd_linux_sem_timeout(u_long arg); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); -static void ahd_linux_size_nseg(void); static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); static void ahd_linux_start_dv(struct ahd_softc *ahd); static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); @@ -516,31 +505,23 @@ static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, u_int); static void ahd_linux_free_device(struct ahd_softc*, struct ahd_linux_device*); -static void ahd_linux_run_device_queue(struct ahd_softc*, - struct ahd_linux_device*); +static int ahd_linux_run_command(struct ahd_softc*, + struct ahd_linux_device*, + struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; static aic_option_callback_t ahd_linux_setup_rd_strm_info; static aic_option_callback_t ahd_linux_setup_dv; static aic_option_callback_t ahd_linux_setup_iocell_info; static int ahd_linux_next_unit(void); -static void ahd_runq_tasklet(unsigned long data); static int aic79xx_setup(char *c); /****************************** Inlines ***************************************/ static __inline void ahd_schedule_completeq(struct ahd_softc *ahd); -static __inline void ahd_schedule_runq(struct ahd_softc *ahd); -static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd); -static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd); static __inline struct ahd_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc); static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd); -static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static __inline struct ahd_linux_device * - ahd_linux_next_device_to_run(struct ahd_softc *ahd); -static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd); static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); static __inline void @@ -553,28 +534,6 @@ ahd_schedule_completeq(struct ahd_softc *ahd) } } -/* - * Must be called with our lock held. - */ -static __inline void -ahd_schedule_runq(struct ahd_softc *ahd) -{ - tasklet_schedule(&ahd->platform_data->runq_tasklet); -} - -static __inline -void ahd_setup_runq_tasklet(struct ahd_softc *ahd) -{ - tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet, - (unsigned long)ahd); -} - -static __inline void -ahd_teardown_runq_tasklet(struct ahd_softc *ahd) -{ - tasklet_kill(&ahd->platform_data->runq_tasklet); -} - static __inline struct ahd_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc) @@ -640,46 +599,6 @@ ahd_linux_run_complete_queue(struct ahd_softc *ahd) return (acmd); } -static __inline void -ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev) -{ - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahd_linux_run_device_queue(ahd, dev); -} - -static __inline struct ahd_linux_device * -ahd_linux_next_device_to_run(struct ahd_softc *ahd) -{ - - if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0 - || (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0)) - return (NULL); - return (TAILQ_FIRST(&ahd->platform_data->device_runq)); -} - -static __inline void -ahd_linux_run_device_queues(struct ahd_softc *ahd) -{ - struct ahd_linux_device *dev; - - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); - } -} - static __inline void ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) { @@ -709,7 +628,6 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) static int ahd_linux_detect(Scsi_Host_Template *); static const char *ahd_linux_info(struct Scsi_Host *); static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahd_linux_slave_alloc(Scsi_Device *); static int ahd_linux_slave_configure(Scsi_Device *); static void ahd_linux_slave_destroy(Scsi_Device *); @@ -717,78 +635,10 @@ static void ahd_linux_slave_destroy(Scsi_Device *); static int ahd_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); #endif -#else -static int ahd_linux_release(struct Scsi_Host *); -static void ahd_linux_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -#if defined(__i386__) -static int ahd_linux_biosparam(Disk *, kdev_t, int[]); -#endif -#endif static int ahd_linux_bus_reset(Scsi_Cmnd *); static int ahd_linux_dev_reset(Scsi_Cmnd *); static int ahd_linux_abort(Scsi_Cmnd *); -/* - * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg). - * - * In pre-2.5.X... - * The midlayer allocates an S/G array dynamically when a command is issued - * using SCSI malloc. This array, which is in an OS dependent format that - * must later be copied to our private S/G list, is sized to house just the - * number of segments needed for the current transfer. Since the code that - * sizes the SCSI malloc pool does not take into consideration fragmentation - * of the pool, executing transactions numbering just a fraction of our - * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will - * quickly depleat the SCSI malloc pool of usable space. Unfortunately, the - * mid-layer does not properly handle this scsi malloc failures for the S/G - * array and the result can be a lockup of the I/O subsystem. We try to size - * our S/G list so that it satisfies our drivers allocation requirements in - * addition to avoiding fragmentation of the SCSI malloc pool. - */ -static void -ahd_linux_size_nseg(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - u_int cur_size; - u_int best_size; - - /* - * The SCSI allocator rounds to the nearest 512 bytes - * an cannot allocate across a page boundary. Our algorithm - * is to start at 1K of scsi malloc space per-command and - * loop through all factors of the PAGE_SIZE and pick the best. - */ - best_size = 0; - for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) { - u_int nseg; - - nseg = cur_size / sizeof(struct scatterlist); - if (nseg < AHD_LINUX_MIN_NSEG) - continue; - - if (best_size == 0) { - best_size = cur_size; - ahd_linux_nseg = nseg; - } else { - u_int best_rem; - u_int cur_rem; - - /* - * Compare the traits of the current "best_size" - * with the current size to determine if the - * current size is a better size. - */ - best_rem = best_size % sizeof(struct scatterlist); - cur_rem = cur_size % sizeof(struct scatterlist); - if (cur_rem < best_rem) { - best_size = cur_size; - ahd_linux_nseg = nseg; - } - } - } -#endif -} /* * Try to detect an Adaptec 79XX controller. @@ -800,14 +650,6 @@ ahd_linux_detect(Scsi_Host_Template *template) int found; int error = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * It is a bug that the upper layer takes - * this lock just prior to calling us. - */ - spin_unlock_irq(&io_request_lock); -#endif - /* * Sanity checking of Linux SCSI data structures so * that some of our hacks^H^H^H^H^Hassumptions aren't @@ -819,10 +661,7 @@ ahd_linux_detect(Scsi_Host_Template *template) printf("ahd_linux_detect: Unable to attach\n"); return (0); } - /* - * Determine an appropriate size for our Scatter Gatther lists. - */ - ahd_linux_size_nseg(); + #ifdef MODULE /* * If we've been passed any parameters, process them now. @@ -855,47 +694,10 @@ ahd_linux_detect(Scsi_Host_Template *template) if (ahd_linux_register_host(ahd, template) == 0) found++; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif aic79xx_detect_complete++; return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - */ -static int -ahd_linux_release(struct Scsi_Host * host) -{ - struct ahd_softc *ahd; - u_long l; - - ahd_list_lock(&l); - if (host != NULL) { - - /* - * We should be able to just perform - * the free directly, but check our - * list for extra sanity. - */ - ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata); - if (ahd != NULL) { - u_long s; - - ahd_lock(ahd, &s); - ahd_intr_enable(ahd, FALSE); - ahd_unlock(ahd, &s); - ahd_free(ahd); - } - } - ahd_list_unlock(&l); - return (0); -} -#endif - /* * Return a string describing the driver. */ @@ -932,17 +734,9 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahd_softc *ahd; struct ahd_linux_device *dev; - u_long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - /* - * Save the callback on completion function. - */ - cmd->scsi_done = scsi_done; - - ahd_midlayer_entrypoint_lock(ahd, &flags); - /* * Close the race of a command that was in the process of * being queued to us just as our simq was frozen. Let @@ -951,39 +745,26 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ if (ahd->platform_data->qfrozen != 0 && AHD_DV_CMD(cmd) == 0) { + printf("%s: queue frozen\n", ahd_name(ahd)); - ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); - ahd_linux_queue_cmd_complete(ahd, cmd); - ahd_schedule_completeq(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &flags); - return (0); + return SCSI_MLQUEUE_HOST_BUSY; } + + /* + * Save the callback on completion function. + */ + cmd->scsi_done = scsi_done; + dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); - if (dev == NULL) { - ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); - ahd_linux_queue_cmd_complete(ahd, cmd); - ahd_schedule_completeq(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &flags); - printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", - ahd_name(ahd)); - return (0); - } - if (cmd->cmd_len > MAX_CDB_LEN) - return (-EINVAL); + BUG_ON(dev == NULL); + cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - ahd_linux_run_device_queues(ahd); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); - return (0); + + return ahd_linux_run_command(ahd, dev, cmd); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahd_linux_slave_alloc(Scsi_Device *device) { @@ -1049,99 +830,22 @@ ahd_linux_slave_destroy(Scsi_Device *device) if (dev != NULL && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { dev->flags |= AHD_DEV_UNCONFIGURED; - if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0 + if (dev->active == 0 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) ahd_linux_free_device(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags); } -#else -/* - * Sets the queue depth for each SCSI device hanging - * off the input host adapter. - */ -static void -ahd_linux_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) -{ - Scsi_Device *device; - Scsi_Device *ldev; - struct ahd_softc *ahd; - u_long flags; - - ahd = *((struct ahd_softc **)host->hostdata); - ahd_lock(ahd, &flags); - for (device = scsi_devs; device != NULL; device = device->next) { - - /* - * Watch out for duplicate devices. This works around - * some quirks in how the SCSI scanning code does its - * device management. - */ - for (ldev = scsi_devs; ldev != device; ldev = ldev->next) { - if (ldev->host == device->host - && ldev->channel == device->channel - && ldev->id == device->id - && ldev->lun == device->lun) - break; - } - /* Skip duplicate. */ - if (ldev != device) - continue; - - if (device->host == host) { - struct ahd_linux_device *dev; - - /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. - */ - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; - dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); - device->queue_depth = dev->openings - + dev->active; - if ((dev->flags & (AHD_DEV_Q_BASIC - | AHD_DEV_Q_TAGGED)) == 0) { - /* - * We allow the OS to queue 2 untagged - * transactions to us at any time even - * though we can only execute them - * serially on the controller/device. - * This should remove some latency. - */ - device->queue_depth = 2; - } - } - } - } - ahd_unlock(ahd, &flags); -} -#endif #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ static int -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { uint8_t *bh; -#else -ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) -{ - struct scsi_device *sdev = disk->device; - u_long capacity = disk->capacity; - struct buffer_head *bh; -#endif int heads; int sectors; int cylinders; @@ -1151,22 +855,11 @@ ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) ahd = *((struct ahd_softc **)sdev->host->hostdata); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) bh = scsi_bios_ptable(bdev); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17) - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); -#else - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024); -#endif - if (bh) { ret = scsi_partsize(bh, capacity, &geom[2], &geom[0], &geom[1]); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) kfree(bh); -#else - brelse(bh); -#endif if (ret != -1) return (ret); } @@ -1198,7 +891,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) { struct ahd_softc *ahd; struct ahd_cmd *acmd; - struct ahd_cmd *list_acmd; struct ahd_linux_device *dev; struct scb *pending_scb; u_long s; @@ -1265,22 +957,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) goto no_cmd; } - TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { - if (list_acmd == acmd) - break; - } - - if (list_acmd != NULL) { - printf("%s:%d:%d:%d: Command found on device queue\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); - cmd->result = DID_ABORT << 16; - ahd_linux_queue_cmd_complete(ahd, cmd); - retval = SUCCESS; - goto done; - } - /* * See if we can find a matching cmd in the pending list. */ @@ -1468,7 +1144,6 @@ done: } spin_lock_irq(&ahd->platform_data->spin_lock); } - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_midlayer_entrypoint_unlock(ahd, &s); return (retval); @@ -1568,7 +1243,6 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) retval = FAILED; } ahd_lock(ahd, &s); - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &s); printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); @@ -1625,35 +1299,6 @@ Scsi_Host_Template aic79xx_driver_template = { .slave_destroy = ahd_linux_slave_destroy, }; -/**************************** Tasklet Handler *********************************/ - -/* - * In 2.4.X and above, this routine is called from a tasklet, - * so we must re-acquire our lock prior to executing this code. - * In all prior kernels, ahd_schedule_runq() calls this routine - * directly and ahd_schedule_runq() is called with our lock held. - */ -static void -ahd_runq_tasklet(unsigned long data) -{ - struct ahd_softc* ahd; - struct ahd_linux_device *dev; - u_long flags; - - ahd = (struct ahd_softc *)data; - ahd_lock(ahd, &flags); - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); - /* Yeild to our interrupt handler */ - ahd_unlock(ahd, &flags); - ahd_lock(ahd, &flags); - } - ahd_unlock(ahd, &flags); -} - /******************************** Bus DMA *************************************/ int ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, @@ -1997,11 +1642,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) *((struct ahd_softc **)host->hostdata) = ahd; ahd_lock(ahd, &s); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahd->platform_data->spin_lock); -#elif AHD_SCSI_HAS_HOST_LOCK != 0 - host->lock = &ahd->platform_data->spin_lock; -#endif ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; @@ -2020,9 +1661,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_set_name(ahd, new_name); } host->unique_id = ahd->unit; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - scsi_set_pci_device(host, ahd->dev_softc); -#endif ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); @@ -2064,10 +1702,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_linux_start_dv(ahd); ahd_unlock(ahd, &s); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ scsi_scan_host(host); -#endif return (0); } @@ -2163,7 +1799,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) return (ENOMEM); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); TAILQ_INIT(&ahd->platform_data->completeq); - TAILQ_INIT(&ahd->platform_data->device_runq); ahd->platform_data->irq = AHD_LINUX_NOIRQ; ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; ahd_lockinit(ahd); @@ -2175,7 +1810,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); - ahd_setup_runq_tasklet(ahd); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0); } @@ -2190,11 +1824,8 @@ ahd_platform_free(struct ahd_softc *ahd) if (ahd->platform_data != NULL) { del_timer_sync(&ahd->platform_data->completeq_timer); ahd_linux_kill_dv_thread(ahd); - ahd_teardown_runq_tasklet(ahd); if (ahd->platform_data->host != NULL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); -#endif scsi_host_put(ahd->platform_data->host); } @@ -2233,16 +1864,6 @@ ahd_platform_free(struct ahd_softc *ahd) release_mem_region(ahd->platform_data->mem_busaddr, 0x1000); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we detach from the scsi midlayer before the PCI - * layer invokes our remove callback. No per-instance - * detach is provided, so we must reach inside the PCI - * subsystem's internals and detach our driver manually. - */ - if (ahd->dev_softc != NULL) - ahd->dev_softc->driver = NULL; -#endif free(ahd->platform_data, M_DEVBUF); } } @@ -2339,7 +1960,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, dev->maxtags = 0; dev->openings = 1 - dev->active; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (dev->scsi_device != NULL) { switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: @@ -2365,65 +1986,13 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, break; } } -#endif } int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status) { - int targ; - int maxtarg; - int maxlun; - int clun; - int count; - - if (tag != SCB_LIST_NULL) - return (0); - - targ = 0; - if (target != CAM_TARGET_WILDCARD) { - targ = target; - maxtarg = targ + 1; - } else { - maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8; - } - clun = 0; - if (lun != CAM_LUN_WILDCARD) { - clun = lun; - maxlun = clun + 1; - } else { - maxlun = AHD_NUM_LUNS; - } - - count = 0; - for (; targ < maxtarg; targ++) { - - for (; clun < maxlun; clun++) { - struct ahd_linux_device *dev; - struct ahd_busyq *busyq; - struct ahd_cmd *acmd; - - dev = ahd_linux_get_device(ahd, /*chan*/0, targ, - clun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - busyq = &dev->busyq; - while ((acmd = TAILQ_FIRST(busyq)) != NULL) { - Scsi_Cmnd *cmd; - - cmd = &acmd_scsi_cmd(acmd); - TAILQ_REMOVE(busyq, acmd, - acmd_links.tqe); - count++; - cmd->result = status << 16; - ahd_linux_queue_cmd_complete(ahd, cmd); - } - } - } - - return (count); + return 0; } static void @@ -2478,18 +2047,10 @@ ahd_linux_dv_thread(void *data) * Complete thread creation. */ lock_kernel(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) - /* - * Don't care about any signals. - */ - siginitsetinv(¤t->blocked, 0); - daemonize(); - sprintf(current->comm, "ahd_dv_%d", ahd->unit); -#else daemonize("ahd_dv_%d", ahd->unit); - current->flags |= PF_NOFREEZE; -#endif + current->flags |= PF_FREEZE; + unlock_kernel(); while (1) { @@ -3685,8 +3246,6 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd) ahd->platform_data->reset_timer.function = (ahd_linux_callback_t *)ahd_release_simq; add_timer(&ahd->platform_data->reset_timer); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); } @@ -3903,11 +3462,10 @@ ahd_linux_device_queue_depth(struct ahd_softc *ahd, } } -static void -ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev) +static int +ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, + struct scsi_cmnd *cmd) { - struct ahd_cmd *acmd; - struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahd_initiator_tinfo *tinfo; @@ -3915,157 +3473,132 @@ ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev) u_int col_idx; uint16_t mask; - if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0) - panic("running device on run list"); - - while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL - && dev->openings > 0 && dev->qfrozen == 0) { - - /* - * Schedule us to run later. The only reason we are not - * running is because the whole controller Q is frozen. - */ - if (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0) { - - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, - dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - return; - } + /* + * Get an scb to use. + */ + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + cmd->device->id, &tstate); + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 + || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { + col_idx = AHD_NEVER_COL_IDX; + } else { + col_idx = AHD_BUILD_COL_IDX(cmd->device->id, + cmd->device->lun); + } + if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { + ahd->flags |= AHD_RESOURCE_SHORTAGE; + return SCSI_MLQUEUE_HOST_BUSY; + } - cmd = &acmd_scsi_cmd(acmd); + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; - /* - * Get an scb to use. - */ - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 - || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - col_idx = AHD_NEVER_COL_IDX; - } else { - col_idx = AHD_BUILD_COL_IDX(cmd->device->id, - cmd->device->lun); - } - if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, - dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - ahd->flags |= AHD_RESOURCE_SHORTAGE; - return; - } - TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahd, cmd); + hscb->lun = cmd->device->lun; + scb->hscb->task_management = 0; + mask = SCB_GET_TARGET_MASK(ahd, scb); - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - scb->hscb->task_management = 0; - mask = SCB_GET_TARGET_MASK(ahd, scb); + if ((ahd->user_discenable & mask) != 0) + hscb->control |= DISCENB; - if ((ahd->user_discenable & mask) != 0) - hscb->control |= DISCENB; + if (AHD_DV_CMD(cmd) != 0) + scb->flags |= SCB_SILENT; - if (AHD_DV_CMD(cmd) != 0) - scb->flags |= SCB_SILENT; + if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) + scb->flags |= SCB_PACKETIZED; - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) - scb->flags |= SCB_PACKETIZED; + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { + int msg_bytes; + uint8_t tag_msgs[2]; - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else -#endif - if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH - && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; + msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); + if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { + hscb->control |= tag_msgs[0]; + if (tag_msgs[0] == MSG_ORDERED_TASK) dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } + } else + if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH + && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; } + } - hscb->cdb_len = cmd->cmd_len; - memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); - - scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - if (cmd->use_sg != 0) { - void *sg; - struct scatterlist *cur_seg; - u_int nseg; - int dir; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - dir = cmd->sc_data_direction; - nseg = pci_map_sg(ahd->dev_softc, cur_seg, - cmd->use_sg, dir); - scb->platform_data->xfer_len = 0; - for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { - dma_addr_t addr; - bus_size_t len; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - scb->platform_data->xfer_len += len; - sg = ahd_sg_setup(ahd, scb, sg, addr, len, - /*last*/nseg == 1); - } - } else if (cmd->request_bufflen != 0) { - void *sg; + hscb->cdb_len = cmd->cmd_len; + memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); + + scb->sg_count = 0; + ahd_set_residual(scb, 0); + ahd_set_sense_residual(scb, 0); + if (cmd->use_sg != 0) { + void *sg; + struct scatterlist *cur_seg; + u_int nseg; + int dir; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + dir = cmd->sc_data_direction; + nseg = pci_map_sg(ahd->dev_softc, cur_seg, + cmd->use_sg, dir); + scb->platform_data->xfer_len = 0; + for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { dma_addr_t addr; - int dir; - - sg = scb->sg_list; - dir = cmd->sc_data_direction; - addr = pci_map_single(ahd->dev_softc, - cmd->request_buffer, - cmd->request_bufflen, dir); - scb->platform_data->xfer_len = cmd->request_bufflen; - scb->platform_data->buf_busaddr = addr; - sg = ahd_sg_setup(ahd, scb, sg, addr, - cmd->request_bufflen, /*last*/TRUE); - } + bus_size_t len; - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - - /* Update the error counting bucket and dump if needed */ - if (dev->target->cmds_since_error) { - dev->target->cmds_since_error++; - if (dev->target->cmds_since_error > - AHD_LINUX_ERR_THRESH) - dev->target->cmds_since_error = 0; + addr = sg_dma_address(cur_seg); + len = sg_dma_len(cur_seg); + scb->platform_data->xfer_len += len; + sg = ahd_sg_setup(ahd, scb, sg, addr, len, + /*last*/nseg == 1); } + } else if (cmd->request_bufflen != 0) { + void *sg; + dma_addr_t addr; + int dir; + + sg = scb->sg_list; + dir = cmd->sc_data_direction; + addr = pci_map_single(ahd->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, dir); + scb->platform_data->xfer_len = cmd->request_bufflen; + scb->platform_data->buf_busaddr = addr; + sg = ahd_sg_setup(ahd, scb, sg, addr, + cmd->request_bufflen, /*last*/TRUE); + } - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - scb->flags |= SCB_ACTIVE; - ahd_queue_scb(ahd, scb); + LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->commands_issued++; + + /* Update the error counting bucket and dump if needed */ + if (dev->target->cmds_since_error) { + dev->target->cmds_since_error++; + if (dev->target->cmds_since_error > + AHD_LINUX_ERR_THRESH) + dev->target->cmds_since_error = 0; } + + if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) + dev->commands_since_idle_or_otag++; + scb->flags |= SCB_ACTIVE; + ahd_queue_scb(ahd, scb); + + return 0; } /* @@ -4081,8 +3614,6 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ours = ahd_intr(ahd); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); return IRQ_RETVAL(ours); @@ -4161,7 +3692,6 @@ ahd_linux_alloc_device(struct ahd_softc *ahd, return (NULL); memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); - TAILQ_INIT(&dev->busyq); dev->flags = AHD_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -4264,28 +3794,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, } case AC_SENT_BDR: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) WARN_ON(lun != CAM_LUN_WILDCARD); scsi_report_device_reset(ahd->platform_data->host, channel - 'A', target); -#else - Scsi_Device *scsi_dev; - - /* - * Find the SCSI device associated with this - * request and indicate that a UA is expected. - */ - for (scsi_dev = ahd->platform_data->host->host_queue; - scsi_dev != NULL; scsi_dev = scsi_dev->next) { - if (channel - 'A' == scsi_dev->channel - && target == scsi_dev->id - && (lun == CAM_LUN_WILDCARD - || lun == scsi_dev->lun)) { - scsi_dev->was_reset = 1; - scsi_dev->expecting_cc_ua = 1; - } - } -#endif break; } case AC_BUS_RESET: @@ -4406,15 +3917,10 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) if (dev->active == 0) dev->commands_since_idle_or_otag = 0; - if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); - } else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - } + if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 + && dev->active == 0 + && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) + ahd_linux_free_device(ahd, dev); if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); @@ -4887,7 +4393,6 @@ ahd_release_simq(struct ahd_softc *ahd) ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE; up(&ahd->platform_data->dv_sem); } - ahd_schedule_runq(ahd); ahd_unlock(ahd, &s); /* * There is still a race here. The mid-layer @@ -4929,61 +4434,16 @@ ahd_linux_dev_timed_unfreeze(u_long arg) dev->flags &= ~AHD_DEV_TIMER_ACTIVE; if (dev->qfrozen > 0) dev->qfrozen--; - if (dev->qfrozen == 0 - && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0) - ahd_linux_run_device_queue(ahd, dev); if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 && dev->active == 0) ahd_linux_free_device(ahd, dev); ahd_unlock(ahd, &s); } -void -ahd_platform_dump_card_state(struct ahd_softc *ahd) -{ - struct ahd_linux_device *dev; - int target; - int maxtarget; - int lun; - int i; - - maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7; - for (target = 0; target <=maxtarget; target++) { - - for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_cmd *acmd; - - dev = ahd_linux_get_device(ahd, 0, target, - lun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - printf("DevQ(%d:%d:%d): ", 0, target, lun); - i = 0; - TAILQ_FOREACH(acmd, &dev->busyq, acmd_links.tqe) { - if (i++ > AHD_SCB_MAX) - break; - } - printf("%d waiting\n", i); - } - } -} - static int __init ahd_linux_init(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return ahd_linux_detect(&aic79xx_driver_template); -#else - scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template); - if (aic79xx_driver_template.present == 0) { - scsi_unregister_module(MODULE_SCSI_HA, - &aic79xx_driver_template); - return (-ENODEV); - } - - return (0); -#endif } static void __exit @@ -5002,14 +4462,6 @@ ahd_linux_exit(void) ahd_linux_kill_dv_thread(ahd); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we have to unregister from the PCI core _after_ - * unregistering from the scsi midlayer to avoid dangling - * references. - */ - scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template); -#endif ahd_linux_pci_exit(); } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 7823e52e99a..792e97fef5b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -252,11 +252,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK)) #define AHD_SCSI_HAS_HOST_LOCK 1 -#else -#define AHD_SCSI_HAS_HOST_LOCK 0 -#endif #define AIC79XX_DRIVER_VERSION "1.3.11" @@ -297,12 +293,11 @@ struct ahd_cmd { * after a successfully completed inquiry command to the target when * that inquiry data indicates a lun is present. */ -TAILQ_HEAD(ahd_busyq, ahd_cmd); + typedef enum { AHD_DEV_UNCONFIGURED = 0x01, AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHD_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ @@ -312,7 +307,6 @@ typedef enum { struct ahd_linux_target; struct ahd_linux_device { TAILQ_ENTRY(ahd_linux_device) links; - struct ahd_busyq busyq; /* * The number of transactions currently @@ -453,18 +447,7 @@ struct ahd_linux_target { * manner and are allocated below 4GB, the number of S/G segments is * unrestricted. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * We dynamically adjust the number of segments in pre-2.5 kernels to - * avoid fragmentation issues in the SCSI mid-layer's private memory - * allocator. See aic79xx_osm.c ahd_linux_size_nseg() for details. - */ -extern u_int ahd_linux_nseg; -#define AHD_NSEG ahd_linux_nseg -#define AHD_LINUX_MIN_NSEG 64 -#else #define AHD_NSEG 128 -#endif /* * Per-SCB OSM storage. @@ -502,11 +485,9 @@ struct ahd_platform_data { * Fields accessed from interrupt context. */ struct ahd_linux_target *targets[AHD_NUM_TARGETS]; - TAILQ_HEAD(, ahd_linux_device) device_runq; struct ahd_completeq completeq; spinlock_t spin_lock; - struct tasklet_struct runq_tasklet; u_int qfrozen; pid_t dv_pid; struct timer_list completeq_timer; @@ -925,12 +906,8 @@ ahd_flush_device_writes(struct ahd_softc *ahd) } /**************************** Proc FS Support *********************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -int ahd_linux_proc_info(char *, char **, off_t, int, int, int); -#else int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -#endif /*************************** Domain Validation ********************************/ #define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) @@ -1117,7 +1094,6 @@ 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 *); void ahd_print_path(struct ahd_softc *, struct scb *); -void ahd_platform_dump_card_state(struct ahd_softc *ahd); #ifdef CONFIG_PCI #define AHD_PCI_CONFIG 1 diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index e01cd6175e3..9c631a494ed 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -278,13 +278,8 @@ done: * Return information to handle /proc support for the driver. */ int -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -ahd_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) -#else ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) -#endif { struct ahd_softc *ahd; struct info_str info; @@ -296,14 +291,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, retval = -EINVAL; ahd_list_lock(&l); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->platform_data->host->host_no == hostno) - break; - } -#else ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); -#endif if (ahd == NULL) goto done; -- cgit v1.2.3 From 73a25462100772b72a5d62fd66dff01b53018618 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 22 Jul 2005 16:44:04 +0200 Subject: [SCSI] aic79xx: update to use scsi_transport_spi This patch updates the aic79xx driver to take advantage of the scsi_transport_spi infrastructure. Patch is quite a mess as some procedures have been reshuffled to be closer to the aic7xxx driver. Rejections fixed and Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 5253 +++++++++++------------------------ drivers/scsi/aic7xxx/aic79xx_osm.h | 197 +- drivers/scsi/aic7xxx/aic79xx_proc.c | 18 +- 3 files changed, 1715 insertions(+), 3753 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 7463dd515d1..70997ca28ba 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -46,6 +46,8 @@ #include "aic79xx_inline.h" #include +static struct scsi_transport_template *ahd_linux_transport_template = NULL; + /* * Include aiclib.c as part of our * "module dependencies are hard" work around. @@ -54,6 +56,7 @@ #include /* __setup */ #include /* For fetching system memory size */ +#include /* For block_size() */ #include /* For ssleep/msleep */ /* @@ -177,71 +180,6 @@ static adapter_tag_info_t aic79xx_tag_info[] = {AIC79XX_CONFIGED_TAG_COMMANDS} }; -/* - * By default, read streaming is disabled. In theory, - * read streaming should enhance performance, but early - * U320 drive firmware actually performs slower with - * read streaming enabled. - */ -#ifdef CONFIG_AIC79XX_ENABLE_RD_STRM -#define AIC79XX_CONFIGED_RD_STRM 0xFFFF -#else -#define AIC79XX_CONFIGED_RD_STRM 0 -#endif - -static uint16_t aic79xx_rd_strm_info[] = -{ - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM -}; - -/* - * DV option: - * - * positive value = DV Enabled - * zero = DV Disabled - * negative value = DV Default for adapter type/seeprom - */ -#ifdef CONFIG_AIC79XX_DV_SETTING -#define AIC79XX_CONFIGED_DV CONFIG_AIC79XX_DV_SETTING -#else -#define AIC79XX_CONFIGED_DV -1 -#endif - -static int8_t aic79xx_dv_settings[] = -{ - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV -}; - /* * The I/O cell on the chip is very configurable in respect to its analog * characteristics. Set the defaults here; they can be overriden with @@ -402,7 +340,7 @@ MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(AIC79XX_DRIVER_VERSION); -module_param(aic79xx, charp, 0); +module_param(aic79xx, charp, 0444); MODULE_PARM_DESC(aic79xx, "period delimited, options string.\n" " verbose Enable verbose/diagnostic logging\n" @@ -417,8 +355,6 @@ MODULE_PARM_DESC(aic79xx, " reverse_scan Sort PCI devices highest Bus/Slot to lowest\n" " tag_info: Set per-target tag depth\n" " global_tag_depth: Global tag depth for all targets on all buses\n" -" rd_strm: Set per-target read streaming setting.\n" -" dv: Set per-controller Domain Validation Setting.\n" " slewrate:Set the signal slew rate (0-15).\n" " precomp: Set the signal precompensation (0-7).\n" " amplitude: Set the signal amplitude (0-7).\n" @@ -431,178 +367,35 @@ MODULE_PARM_DESC(aic79xx, " Shorten the selection timeout to 128ms\n" "\n" " options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n" -"\n" -" Sample /etc/modprobe.conf line:\n" -" Change Read Streaming for Controller's 2 and 3\n" -"\n" -" options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'"); +"\n"); static void ahd_linux_handle_scsi_status(struct ahd_softc *, - struct ahd_linux_device *, + struct scsi_device *, struct scb *); static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, - Scsi_Cmnd *cmd); -static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dev_timed_unfreeze(u_long arg); + struct scsi_cmnd *cmd); static void ahd_linux_sem_timeout(u_long arg); +static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); -static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); -static void ahd_linux_start_dv(struct ahd_softc *ahd); -static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); -static int ahd_linux_dv_thread(void *data); -static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd); -static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target); -static void ahd_linux_dv_transition(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_inq(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ, - u_int request_length); -static void ahd_linux_dv_tur(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_rebd(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_web(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_reb(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_su(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static int ahd_linux_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_complete(Scsi_Cmnd *cmd); -static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); -static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd); -static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd); -static void ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc*, - u_int, u_int); -static void ahd_linux_free_target(struct ahd_softc*, - struct ahd_linux_target*); -static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, - struct ahd_linux_target*, - u_int); -static void ahd_linux_free_device(struct ahd_softc*, - struct ahd_linux_device*); +static void ahd_linux_device_queue_depth(struct scsi_device *); static int ahd_linux_run_command(struct ahd_softc*, - struct ahd_linux_device*, + struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; -static aic_option_callback_t ahd_linux_setup_rd_strm_info; -static aic_option_callback_t ahd_linux_setup_dv; static aic_option_callback_t ahd_linux_setup_iocell_info; -static int ahd_linux_next_unit(void); -static int aic79xx_setup(char *c); +static int aic79xx_setup(char *c); +static int ahd_linux_next_unit(void); /****************************** Inlines ***************************************/ -static __inline void ahd_schedule_completeq(struct ahd_softc *ahd); -static __inline struct ahd_linux_device* - ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, - u_int target, u_int lun, int alloc); -static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd); static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); -static __inline void -ahd_schedule_completeq(struct ahd_softc *ahd) -{ - if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) { - ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER; - ahd->platform_data->completeq_timer.expires = jiffies; - add_timer(&ahd->platform_data->completeq_timer); - } -} - -static __inline struct ahd_linux_device* -ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, - u_int lun, int alloc) -{ - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; - u_int target_offset; - - target_offset = target; - if (channel != 0) - target_offset += 8; - targ = ahd->platform_data->targets[target_offset]; - if (targ == NULL) { - if (alloc != 0) { - targ = ahd_linux_alloc_target(ahd, channel, target); - if (targ == NULL) - return (NULL); - } else - return (NULL); - } - dev = targ->devices[lun]; - if (dev == NULL && alloc != 0) - dev = ahd_linux_alloc_device(ahd, targ, lun); - return (dev); -} - -#define AHD_LINUX_MAX_RETURNED_ERRORS 4 -static struct ahd_cmd * -ahd_linux_run_complete_queue(struct ahd_softc *ahd) -{ - struct ahd_cmd *acmd; - u_long done_flags; - int with_errors; - - with_errors = 0; - ahd_done_lock(ahd, &done_flags); - while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) { - Scsi_Cmnd *cmd; - - if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) { - /* - * Linux uses stack recursion to requeue - * commands that need to be retried. Avoid - * blowing out the stack by "spoon feeding" - * commands that completed with error back - * the operating system in case they are going - * to be retried. "ick" - */ - ahd_schedule_completeq(ahd); - break; - } - TAILQ_REMOVE(&ahd->platform_data->completeq, - acmd, acmd_links.tqe); - cmd = &acmd_scsi_cmd(acmd); - cmd->host_scribble = NULL; - if (ahd_cmd_get_transaction_status(cmd) != DID_OK - || (cmd->result & 0xFF) != SCSI_STATUS_OK) - with_errors++; - - cmd->scsi_done(cmd); - } - ahd_done_unlock(ahd, &done_flags); - return (acmd); -} - static __inline void ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; int direction; cmd = scb->io_ctx; @@ -624,51 +417,21 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) #define BUILD_SCSIID(ahd, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id) -/************************ Host template entry points *************************/ -static int ahd_linux_detect(Scsi_Host_Template *); -static const char *ahd_linux_info(struct Scsi_Host *); -static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -static int ahd_linux_slave_alloc(Scsi_Device *); -static int ahd_linux_slave_configure(Scsi_Device *); -static void ahd_linux_slave_destroy(Scsi_Device *); -#if defined(__i386__) -static int ahd_linux_biosparam(struct scsi_device*, - struct block_device*, sector_t, int[]); -#endif -static int ahd_linux_bus_reset(Scsi_Cmnd *); -static int ahd_linux_dev_reset(Scsi_Cmnd *); -static int ahd_linux_abort(Scsi_Cmnd *); - - /* * Try to detect an Adaptec 79XX controller. */ static int -ahd_linux_detect(Scsi_Host_Template *template) +ahd_linux_detect(struct scsi_host_template *template) { struct ahd_softc *ahd; int found; int error = 0; - /* - * Sanity checking of Linux SCSI data structures so - * that some of our hacks^H^H^H^H^Hassumptions aren't - * violated. - */ - if (offsetof(struct ahd_cmd_internal, end) - > offsetof(struct scsi_cmnd, host_scribble)) { - printf("ahd_linux_detect: SCSI data structures changed.\n"); - printf("ahd_linux_detect: Unable to attach\n"); - return (0); - } - -#ifdef MODULE /* * If we've been passed any parameters, process them now. */ if (aic79xx) aic79xx_setup(aic79xx); -#endif template->proc_name = "aic79xx"; @@ -695,7 +458,7 @@ ahd_linux_detect(Scsi_Host_Template *template) found++; } aic79xx_detect_complete++; - return 0; + return found; } /* @@ -730,10 +493,10 @@ ahd_linux_info(struct Scsi_Host *host) * Queue an SCB to the controller. */ static int -ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; + struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -743,8 +506,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) * DV commands through so long as we are only frozen to * perform DV. */ - if (ahd->platform_data->qfrozen != 0 - && AHD_DV_CMD(cmd) == 0) { + if (ahd->platform_data->qfrozen != 0) { printf("%s: queue frozen\n", ahd_name(ahd)); return SCSI_MLQUEUE_HOST_BUSY; @@ -755,86 +517,142 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ cmd->scsi_done = scsi_done; - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, cmd->device->lun, - /*alloc*/TRUE); - BUG_ON(dev == NULL); - cmd->result = CAM_REQ_INPROG << 16; return ahd_linux_run_command(ahd, dev, cmd); } +static inline struct scsi_target ** +ahd_linux_target_in_softc(struct scsi_target *starget) +{ + struct ahd_softc *ahd = + *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); + unsigned int target_offset; + + target_offset = starget->id; + if (starget->channel != 0) + target_offset += 8; + + return &ahd->platform_data->starget[target_offset]; +} + static int -ahd_linux_slave_alloc(Scsi_Device *device) +ahd_linux_target_alloc(struct scsi_target *starget) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = + *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); + 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; + char channel = starget->channel + 'A'; - ahd = *((struct ahd_softc **)device->host->hostdata); - if (bootverbose) - printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id); - return (0); + ahd_lock(ahd, &flags); + + BUG_ON(*ahd_targp != NULL); + + *ahd_targp = starget; + memset(targ, 0, sizeof(*targ)); + + tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, + starget->id, &tstate); + ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, + CAM_LUN_WILDCARD, channel, + ROLE_INITIATOR); + spi_min_period(starget) = AHD_SYNCRATE_MAX; /* We can do U320 */ + if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) + spi_max_offset(starget) = MAX_OFFSET_PACED_BUG; + else + spi_max_offset(starget) = MAX_OFFSET_PACED; + spi_max_width(starget) = ahd->features & AHD_WIDE; + + ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, + AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_unlock(ahd, &flags); + + return 0; +} + +static void +ahd_linux_target_destroy(struct scsi_target *starget) +{ + struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); + + *ahd_targp = NULL; } static int -ahd_linux_slave_configure(Scsi_Device *device) +ahd_linux_slave_alloc(struct scsi_device *sdev) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev; - u_long flags; + 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; - ahd = *((struct ahd_softc **)device->host->hostdata); if (bootverbose) - printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id); - ahd_midlayer_entrypoint_lock(ahd, &flags); + 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)); + + /* + * We start out life using untagged + * transactions of which we allow one. + */ + dev->openings = 1; + /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. + * Set maxtags to 0. This will be changed if we + * later determine that we are dealing with + * a tagged queuing capable device. */ - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; - dev->flags |= AHD_DEV_SLAVE_CONFIGURED; - dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); + dev->maxtags = 0; + + targ->sdev[sdev->lun] = sdev; + return (0); } +static int +ahd_linux_slave_configure(struct scsi_device *sdev) +{ + struct ahd_softc *ahd; + + ahd = *((struct ahd_softc **)sdev->host->hostdata); + if (bootverbose) + printf("%s: Slave Configure %d\n", ahd_name(ahd), sdev->id); + + ahd_linux_device_queue_depth(sdev); + + /* Initial Domain Validation */ + if (!spi_initial_dv(sdev->sdev_target)) + spi_dv_device(sdev); + + return 0; +} + static void -ahd_linux_slave_destroy(Scsi_Device *device) +ahd_linux_slave_destroy(struct scsi_device *sdev) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; - u_long flags; + 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 **)device->host->hostdata); + ahd = *((struct ahd_softc **)sdev->host->hostdata); if (bootverbose) - printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id); - ahd_midlayer_entrypoint_lock(ahd, &flags); - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/FALSE); + printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); + + BUG_ON(dev->active); + + targ->sdev[sdev->lun] = NULL; - /* - * Filter out "silly" deletions of real devices by only - * deleting devices that have had slave_configure() - * called on them. All other devices that have not - * been configured will automatically be deleted by - * the refcounting process. - */ - if (dev != NULL - && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { - dev->flags |= AHD_DEV_UNCONFIGURED; - if (dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); } #if defined(__i386__) @@ -887,3582 +705,1861 @@ ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, * Abort the current SCSI command(s). */ static int -ahd_linux_abort(Scsi_Cmnd *cmd) +ahd_linux_abort(struct scsi_cmnd *cmd) +{ + int error; + + error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT); + if (error != 0) + printf("aic79xx_abort returns 0x%x\n", error); + return error; +} + +/* + * Attempt to send a target reset message to the device that timed out. + */ +static int +ahd_linux_dev_reset(struct scsi_cmnd *cmd) +{ + int error; + + error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + if (error != 0) + printf("aic79xx_dev_reset returns 0x%x\n", error); + return error; +} + +/* + * Reset the SCSI bus. + */ +static int +ahd_linux_bus_reset(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; - struct ahd_cmd *acmd; - struct ahd_linux_device *dev; - struct scb *pending_scb; u_long s; - u_int saved_scbptr; - u_int active_scbptr; - u_int last_phase; - u_int cdb_byte; - int retval; - int was_paused; - int paused; - int wait; - int disconnected; - ahd_mode_state saved_modes; + int found; - pending_scb = NULL; - paused = FALSE; - wait = FALSE; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - acmd = (struct ahd_cmd *)cmd; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) + printf("%s: Bus reset called for cmd %p\n", + ahd_name(ahd), cmd); +#endif + ahd_lock(ahd, &s); + found = ahd_reset_channel(ahd, cmd->device->channel + 'A', + /*initiate reset*/TRUE); + ahd_unlock(ahd, &s); - printf("%s:%d:%d:%d: Attempting to abort cmd %p:", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun, cmd); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printf(" 0x%x", cmd->cmnd[cdb_byte]); - printf("\n"); + if (bootverbose) + printf("%s: SCSI bus reset delivered. " + "%d SCBs aborted.\n", ahd_name(ahd), found); - /* - * In all versions of Linux, we have to work around - * a major flaw in how the mid-layer is locked down - * if we are to sleep successfully in our error handler - * while allowing our interrupt handler to run. Since - * the midlayer acquires either the io_request_lock or - * our lock prior to calling us, we must use the - * spin_unlock_irq() method for unlocking our lock. - * This will force interrupts to be enabled on the - * current CPU. Since the EH thread should not have - * been running with CPU interrupts disabled other than - * by acquiring either the io_request_lock or our own - * lock, this *should* be safe. - */ - ahd_midlayer_entrypoint_lock(ahd, &s); + return (SUCCESS); +} - /* - * First determine if we currently own this command. - * Start by searching the device queue. If not found - * there, check the pending_scb list. If not found - * at all, and the system wanted us to just abort the - * command, return success. - */ - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, cmd->device->lun, - /*alloc*/FALSE); +struct scsi_host_template aic79xx_driver_template = { + .module = THIS_MODULE, + .name = "aic79xx", + .proc_info = ahd_linux_proc_info, + .info = ahd_linux_info, + .queuecommand = ahd_linux_queue, + .eh_abort_handler = ahd_linux_abort, + .eh_device_reset_handler = ahd_linux_dev_reset, + .eh_bus_reset_handler = ahd_linux_bus_reset, +#if defined(__i386__) + .bios_param = ahd_linux_biosparam, +#endif + .can_queue = AHD_MAX_QUEUE, + .this_id = -1, + .cmd_per_lun = 2, + .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, +}; - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - printf("%s:%d:%d:%d: Is not an active device\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto no_cmd; - } +/******************************** Bus DMA *************************************/ +int +ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, + bus_size_t alignment, bus_size_t boundary, + dma_addr_t lowaddr, dma_addr_t highaddr, + bus_dma_filter_t *filter, void *filterarg, + bus_size_t maxsize, int nsegments, + bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) +{ + bus_dma_tag_t dmat; + + dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); + if (dmat == NULL) + return (ENOMEM); /* - * See if we can find a matching cmd in the pending list. + * Linux is very simplistic about DMA memory. For now don't + * maintain all specification information. Once Linux supplies + * better facilities for doing these operations, or the + * needs of this particular driver change, we might need to do + * more here. */ - LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } + dmat->alignment = alignment; + dmat->boundary = boundary; + dmat->maxsize = maxsize; + *ret_tag = dmat; + return (0); +} - if (pending_scb == NULL) { - printf("%s:%d:%d:%d: Command not found\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - goto no_cmd; - } +void +ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat) +{ + free(dmat, M_DEVBUF); +} - if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { - /* - * We can't queue two recovery actions using the same SCB - */ - retval = FAILED; - goto done; - } +int +ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, + int flags, bus_dmamap_t *mapp) +{ + *vaddr = pci_alloc_consistent(ahd->dev_softc, + dmat->maxsize, mapp); + if (*vaddr == NULL) + return (ENOMEM); + return(0); +} +void +ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, + void* vaddr, bus_dmamap_t map) +{ + pci_free_consistent(ahd->dev_softc, dmat->maxsize, + vaddr, map); +} + +int +ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, + void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, + void *cb_arg, int flags) +{ /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this cmd. + * Assume for now that this will only be used during + * initialization and not for per-transaction buffer mapping. */ - was_paused = ahd_is_paused(ahd); - ahd_pause_and_flushwork(ahd); - paused = TRUE; - - if ((pending_scb->flags & SCB_ACTIVE) == 0) { - printf("%s:%d:%d:%d: Command already completed\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - goto no_cmd; - } + bus_dma_segment_t stack_sg; - printf("%s: At time of recovery, card was %spaused\n", - ahd_name(ahd), was_paused ? "" : "not "); - ahd_dump_card_state(ahd); + stack_sg.ds_addr = map; + stack_sg.ds_len = dmat->maxsize; + cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); + return (0); +} - disconnected = TRUE; - if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A', - cmd->device->lun, SCB_GET_TAG(pending_scb), - ROLE_INITIATOR, CAM_REQ_ABORTED, - SEARCH_COMPLETE) > 0) { - printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto done; - } +void +ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) +{ +} - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - last_phase = ahd_inb(ahd, LASTPHASE); - saved_scbptr = ahd_get_scbptr(ahd); - active_scbptr = saved_scbptr; - if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { - struct scb *bus_scb; +int +ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) +{ + /* Nothing to do */ + return (0); +} - bus_scb = ahd_lookup_scb(ahd, active_scbptr); - if (bus_scb == pending_scb) - disconnected = FALSE; - } +/********************* Platform Dependent Functions ***************************/ +/* + * Compare "left hand" softc with "right hand" softc, returning: + * < 0 - lahd has a lower priority than rahd + * 0 - Softcs are equal + * > 0 - lahd has a higher priority than rahd + */ +int +ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) +{ + int value; /* - * At this point, pending_scb is the scb associated with the - * passed in command. That command is currently active on the - * bus or is in the disconnected state. + * Under Linux, cards are ordered as follows: + * 1) PCI devices that are marked as the boot controller. + * 2) PCI devices with BIOS enabled sorted by bus/slot/func. + * 3) All remaining PCI devices sorted by bus/slot/func. */ - if (last_phase != P_BUSFREE - && SCB_GET_TAG(pending_scb) == active_scbptr) { +#if 0 + value = (lahd->flags & AHD_BOOT_CHANNEL) + - (rahd->flags & AHD_BOOT_CHANNEL); + if (value != 0) + /* Controllers set for boot have a *higher* priority */ + return (value); +#endif - /* - * We're active on the bus, so assert ATN - * and hope that the target responds. - */ - pending_scb = ahd_lookup_scb(ahd, active_scbptr); - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, SCSISIGO, last_phase|ATNO); - printf("%s:%d:%d:%d: Device is active, asserting ATN\n", - ahd_name(ahd), cmd->device->channel, - cmd->device->id, cmd->device->lun); - wait = TRUE; - } else if (disconnected) { + value = (lahd->flags & AHD_BIOS_ENABLED) + - (rahd->flags & AHD_BIOS_ENABLED); + if (value != 0) + /* Controllers with BIOS enabled have a *higher* priority */ + return (value); - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - */ - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); - pending_scb->hscb->cdb_len = 0; - pending_scb->hscb->task_attribute = 0; - pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; + /* Still equal. Sort by bus/slot/func. */ + if (aic79xx_reverse_scan != 0) + value = ahd_get_pci_bus(lahd->dev_softc) + - ahd_get_pci_bus(rahd->dev_softc); + else + value = ahd_get_pci_bus(rahd->dev_softc) + - ahd_get_pci_bus(lahd->dev_softc); + if (value != 0) + return (value); + if (aic79xx_reverse_scan != 0) + value = ahd_get_pci_slot(lahd->dev_softc) + - ahd_get_pci_slot(rahd->dev_softc); + else + value = ahd_get_pci_slot(rahd->dev_softc) + - ahd_get_pci_slot(lahd->dev_softc); + if (value != 0) + return (value); - if ((pending_scb->flags & SCB_PACKETIZED) != 0) { - /* - * Mark the SCB has having an outstanding - * task management function. Should the command - * complete normally before the task management - * function can be sent, the host will be notified - * to abort our requeued SCB. - */ - ahd_outb(ahd, SCB_TASK_MANAGEMENT, - pending_scb->hscb->task_management); - } else { - /* - * If non-packetized, set the MK_MESSAGE control - * bit indicating that we desire to send a message. - * We also set the disconnected flag since there is - * no guarantee that our SCB control byte matches - * the version on the card. We don't want the - * sequencer to abort the command thinking an - * unsolicited reselection occurred. - */ - pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + value = rahd->channel - lahd->channel; + return (value); +} - /* - * The sequencer will never re-reference the - * in-core SCB. To make sure we are notified - * during reslection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); - } +static void +ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) +{ - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahd_search_qinfifo(ahd, cmd->device->id, - cmd->device->channel + 'A', cmd->device->lun, - SCB_LIST_NULL, ROLE_INITIATOR, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - ahd_qinfifo_requeue_tail(ahd, pending_scb); - ahd_set_scbptr(ahd, saved_scbptr); - ahd_print_path(ahd, pending_scb); - printf("Device is disconnected, re-queuing SCB\n"); - wait = TRUE; - } else { - printf("%s:%d:%d:%d: Unable to deliver message\n", - ahd_name(ahd), cmd->device->channel, - cmd->device->id, cmd->device->lun); - retval = FAILED; - goto done; + if ((instance >= 0) + && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { + uint8_t *iocell_info; + + iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; + iocell_info[index] = value & 0xFFFF; + if (bootverbose) + printf("iocell[%d:%ld] = %d\n", instance, index, value); } +} -no_cmd: - /* - * Our assumption is that if we don't have the command, no - * recovery action was required, so we return success. Again, - * the semantics of the mid-layer recovery engine are not - * well defined, so this may change in time. - */ - retval = SUCCESS; -done: - if (paused) - ahd_unpause(ahd); - if (wait) { - struct timer_list timer; - int ret; +static void +ahd_linux_setup_tag_info_global(char *p) +{ + int tags, i, j; - pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; - spin_unlock_irq(&ahd->platform_data->spin_lock); - init_timer(&timer); - timer.data = (u_long)pending_scb; - timer.expires = jiffies + (5 * HZ); - timer.function = ahd_linux_sem_timeout; - add_timer(&timer); - printf("Recovery code sleeping\n"); - down(&ahd->platform_data->eh_sem); - printf("Recovery code awake\n"); - ret = del_timer_sync(&timer); - if (ret == 0) { - printf("Timer Expired\n"); - retval = FAILED; + tags = simple_strtoul(p + 1, NULL, 0) & 0xff; + printf("Setting Global Tags= %d\n", tags); + + for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) { + for (j = 0; j < AHD_NUM_TARGETS; j++) { + aic79xx_tag_info[i].tag_commands[j] = tags; } - spin_lock_irq(&ahd->platform_data->spin_lock); } - ahd_linux_run_complete_queue(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &s); - return (retval); } - static void -ahd_linux_dev_reset_complete(Scsi_Cmnd *cmd) +ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) { - free(cmd, M_DEVBUF); -} -/* - * Attempt to send a target reset message to the device that timed out. - */ -static int -ahd_linux_dev_reset(Scsi_Cmnd *cmd) -{ - struct ahd_softc *ahd; - struct scsi_cmnd *recovery_cmd; - struct ahd_linux_device *dev; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - struct scb *scb; - struct hardware_scb *hscb; - u_long s; - struct timer_list timer; - int retval; - - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK); - if (!recovery_cmd) - return (FAILED); - memset(recovery_cmd, 0, sizeof(struct scsi_cmnd)); - recovery_cmd->device = cmd->device; - recovery_cmd->scsi_done = ahd_linux_dev_reset_complete; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s:%d:%d:%d: Device reset called for cmd %p\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun, cmd); -#endif - ahd_lock(ahd, &s); - - dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, - cmd->device->lun, /*alloc*/FALSE); - if (dev == NULL) { - ahd_unlock(ahd, &s); - kfree(recovery_cmd); - return (FAILED); - } - if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) { - ahd_unlock(ahd, &s); - kfree(recovery_cmd); - return (FAILED); - } - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - recovery_cmd->result = CAM_REQ_INPROG << 16; - recovery_cmd->host_scribble = (char *)scb; - scb->io_ctx = recovery_cmd; - scb->platform_data->dev = dev; - scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - hscb = scb->hscb; - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - hscb->cdb_len = 0; - hscb->task_management = SIU_TASKMGMT_LUN_RESET; - scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE; - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - scb->flags |= SCB_PACKETIZED; - } else { - hscb->control |= MK_MESSAGE; - } - dev->openings--; - dev->active++; - dev->commands_issued++; - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - ahd_queue_scb(ahd, scb); - - scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; - ahd_unlock(ahd, &s); - init_timer(&timer); - timer.data = (u_long)scb; - timer.expires = jiffies + (5 * HZ); - timer.function = ahd_linux_sem_timeout; - add_timer(&timer); - printf("Recovery code sleeping\n"); - down(&ahd->platform_data->eh_sem); - printf("Recovery code awake\n"); - retval = SUCCESS; - if (del_timer_sync(&timer) == 0) { - printf("Timer Expired\n"); - retval = FAILED; + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic79xx_tag_info)) + && (targ < AHD_NUM_TARGETS)) { + aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; + if (bootverbose) + printf("tag_info[%d:%d] = %d\n", instance, targ, value); } - ahd_lock(ahd, &s); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &s); - printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); - return (retval); } /* - * Reset the SCSI bus. + * Handle Linux boot parameters. This routine allows for assigning a value + * to a parameter with a ':' between the parameter and the value. + * ie. aic79xx=stpwlev:1,extended */ static int -ahd_linux_bus_reset(Scsi_Cmnd *cmd) +aic79xx_setup(char *s) { - struct ahd_softc *ahd; - u_long s; - int found; + int i, n; + char *p; + char *end; - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; + static struct { + const char *name; + uint32_t *flag; + } options[] = { + { "extended", &aic79xx_extended }, + { "no_reset", &aic79xx_no_reset }, + { "verbose", &aic79xx_verbose }, + { "allow_memio", &aic79xx_allow_memio}, #ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s: Bus reset called for cmd %p\n", - ahd_name(ahd), cmd); + { "debug", &ahd_debug }, #endif - ahd_lock(ahd, &s); - found = ahd_reset_channel(ahd, cmd->device->channel + 'A', - /*initiate reset*/TRUE); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &s); + { "reverse_scan", &aic79xx_reverse_scan }, + { "periodic_otag", &aic79xx_periodic_otag }, + { "pci_parity", &aic79xx_pci_parity }, + { "seltime", &aic79xx_seltime }, + { "tag_info", NULL }, + { "global_tag_depth", NULL}, + { "slewrate", NULL }, + { "precomp", NULL }, + { "amplitude", NULL }, + }; - if (bootverbose) - printf("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahd_name(ahd), found); + end = strchr(s, '\0'); - return (SUCCESS); + /* + * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS + * will never be 0 in this case. + */ + n = 0; + + while ((p = strsep(&s, ",.")) != NULL) { + if (*p == '\0') + continue; + for (i = 0; i < NUM_ELEMENTS(options); i++) { + + n = strlen(options[i].name); + if (strncmp(options[i].name, p, n) == 0) + break; + } + if (i == NUM_ELEMENTS(options)) + continue; + + if (strncmp(p, "global_tag_depth", n) == 0) { + ahd_linux_setup_tag_info_global(p + n); + } else if (strncmp(p, "tag_info", n) == 0) { + s = aic_parse_brace_option("tag_info", p + n, end, + 2, ahd_linux_setup_tag_info, 0); + } else if (strncmp(p, "slewrate", n) == 0) { + s = aic_parse_brace_option("slewrate", + p + n, end, 1, ahd_linux_setup_iocell_info, + AIC79XX_SLEWRATE_INDEX); + } else if (strncmp(p, "precomp", n) == 0) { + s = aic_parse_brace_option("precomp", + p + n, end, 1, ahd_linux_setup_iocell_info, + AIC79XX_PRECOMP_INDEX); + } else if (strncmp(p, "amplitude", n) == 0) { + s = aic_parse_brace_option("amplitude", + p + n, end, 1, ahd_linux_setup_iocell_info, + AIC79XX_AMPLITUDE_INDEX); + } else if (p[n] == ':') { + *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); + } else if (!strncmp(p, "verbose", n)) { + *(options[i].flag) = 1; + } else { + *(options[i].flag) ^= 0xFFFFFFFF; + } + } + return 1; } -Scsi_Host_Template aic79xx_driver_template = { - .module = THIS_MODULE, - .name = "aic79xx", - .proc_info = ahd_linux_proc_info, - .info = ahd_linux_info, - .queuecommand = ahd_linux_queue, - .eh_abort_handler = ahd_linux_abort, - .eh_device_reset_handler = ahd_linux_dev_reset, - .eh_bus_reset_handler = ahd_linux_bus_reset, -#if defined(__i386__) - .bios_param = ahd_linux_biosparam, -#endif - .can_queue = AHD_MAX_QUEUE, - .this_id = -1, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .slave_alloc = ahd_linux_slave_alloc, - .slave_configure = ahd_linux_slave_configure, - .slave_destroy = ahd_linux_slave_destroy, -}; +__setup("aic79xx=", aic79xx_setup); + +uint32_t aic79xx_verbose; -/******************************** Bus DMA *************************************/ int -ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - dma_addr_t lowaddr, dma_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) +ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *template) { - bus_dma_tag_t dmat; + char buf[80]; + struct Scsi_Host *host; + char *new_name; + u_long s; - dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT); - if (dmat == NULL) + template->name = ahd->description; + host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); + if (host == NULL) return (ENOMEM); - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; + *((struct ahd_softc **)host->hostdata) = ahd; + ahd_lock(ahd, &s); + scsi_assign_lock(host, &ahd->platform_data->spin_lock); + ahd->platform_data->host = host; + host->can_queue = AHD_MAX_QUEUE; + host->cmd_per_lun = 2; + host->sg_tablesize = AHD_NSEG; + host->this_id = ahd->our_id; + host->irq = ahd->platform_data->irq; + host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8; + host->max_lun = AHD_NUM_LUNS; + host->max_channel = 0; + host->sg_tablesize = AHD_NSEG; + ahd_set_unit(ahd, ahd_linux_next_unit()); + sprintf(buf, "scsi%d", host->host_no); + new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (new_name != NULL) { + strcpy(new_name, buf); + ahd_set_name(ahd, new_name); + } + host->unique_id = ahd->unit; + ahd_linux_initialize_scsi_bus(ahd); + ahd_intr_enable(ahd, TRUE); + ahd_unlock(ahd, &s); + + host->transportt = ahd_linux_transport_template; + + scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ + scsi_scan_host(host); return (0); } -void -ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat) +uint64_t +ahd_linux_get_memsize(void) { - free(dmat, M_DEVBUF); + struct sysinfo si; + + si_meminfo(&si); + return ((uint64_t)si.totalram << PAGE_SHIFT); } -int -ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) +/* + * Find the smallest available unit number to use + * for a new device. We don't just use a static + * count to handle the "repeated hot-(un)plug" + * scenario. + */ +static int +ahd_linux_next_unit(void) { - bus_dmamap_t map; + struct ahd_softc *ahd; + int unit; - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if (ahd->dev_softc != NULL) - if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) { - printk(KERN_WARNING "aic79xx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); - } - *vaddr = pci_alloc_consistent(ahd->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahd->dev_softc != NULL) - if (pci_set_dma_mask(ahd->dev_softc, - ahd->platform_data->hw_dma_mask)) { - printk(KERN_WARNING "aic79xx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); + unit = 0; +retry: + TAILQ_FOREACH(ahd, &ahd_tailq, links) { + if (ahd->unit == unit) { + unit++; + goto retry; } - if (*vaddr == NULL) - return (ENOMEM); - *mapp = map; - return(0); + } + return (unit); } -void -ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ - pci_free_consistent(ahd->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); -} - -int -ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) +/* + * Place the SCSI bus into a known state by either resetting it, + * or forcing transfer negotiations on the next command to any + * target. + */ +static void +ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) { - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; + u_int target_id; + u_int numtarg; - stack_sg.ds_addr = map->bus_addr; - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} + target_id = 0; + numtarg = 0; + + if (aic79xx_no_reset != 0) + ahd->flags &= ~AHD_RESET_BUS_A; + + if ((ahd->flags & AHD_RESET_BUS_A) != 0) + ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE); + else + numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; -void -ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) -{ /* - * The map may is NULL in our < 2.3.X implementation. + * Force negotiation to async for all targets that + * will not see an initial bus reset. */ - if (map != NULL) - free(map, M_DEVBUF); + for (; target_id < numtarg; target_id++) { + struct ahd_devinfo devinfo; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; + + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + target_id, &tstate); + ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, + CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); + ahd_update_neg_request(ahd, &devinfo, tstate, + tinfo, AHD_NEG_ALWAYS); + } + /* Give the bus some time to recover */ + if ((ahd->flags & AHD_RESET_BUS_A) != 0) { + ahd_freeze_simq(ahd); + init_timer(&ahd->platform_data->reset_timer); + ahd->platform_data->reset_timer.data = (u_long)ahd; + ahd->platform_data->reset_timer.expires = + jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; + ahd->platform_data->reset_timer.function = + (ahd_linux_callback_t *)ahd_release_simq; + add_timer(&ahd->platform_data->reset_timer); + } } int -ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) +ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) { - /* Nothing to do */ + ahd->platform_data = + malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT); + if (ahd->platform_data == NULL) + return (ENOMEM); + memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); + ahd->platform_data->irq = AHD_LINUX_NOIRQ; + ahd_lockinit(ahd); + init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); + ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0); } -/********************* Platform Dependent Functions ***************************/ -/* - * Compare "left hand" softc with "right hand" softc, returning: - * < 0 - lahd has a lower priority than rahd - * 0 - Softcs are equal - * > 0 - lahd has a higher priority than rahd - */ -int -ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) +void +ahd_platform_free(struct ahd_softc *ahd) { - int value; - - /* - * Under Linux, cards are ordered as follows: - * 1) PCI devices that are marked as the boot controller. - * 2) PCI devices with BIOS enabled sorted by bus/slot/func. - * 3) All remaining PCI devices sorted by bus/slot/func. - */ -#if 0 - value = (lahd->flags & AHD_BOOT_CHANNEL) - - (rahd->flags & AHD_BOOT_CHANNEL); - if (value != 0) - /* Controllers set for boot have a *higher* priority */ - return (value); -#endif + struct scsi_target *starget; + int i, j; - value = (lahd->flags & AHD_BIOS_ENABLED) - - (rahd->flags & AHD_BIOS_ENABLED); - if (value != 0) - /* Controllers with BIOS enabled have a *higher* priority */ - return (value); + if (ahd->platform_data != NULL) { + if (ahd->platform_data->host != NULL) { + scsi_remove_host(ahd->platform_data->host); + scsi_host_put(ahd->platform_data->host); + } - /* Still equal. Sort by bus/slot/func. */ - if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_bus(lahd->dev_softc) - - ahd_get_pci_bus(rahd->dev_softc); - else - value = ahd_get_pci_bus(rahd->dev_softc) - - ahd_get_pci_bus(lahd->dev_softc); - if (value != 0) - return (value); - if (aic79xx_reverse_scan != 0) - value = ahd_get_pci_slot(lahd->dev_softc) - - ahd_get_pci_slot(rahd->dev_softc); - else - value = ahd_get_pci_slot(rahd->dev_softc) - - ahd_get_pci_slot(lahd->dev_softc); - if (value != 0) - return (value); + /* 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; + } + } - value = rahd->channel - lahd->channel; - return (value); + if (ahd->platform_data->irq != AHD_LINUX_NOIRQ) + free_irq(ahd->platform_data->irq, ahd); + if (ahd->tags[0] == BUS_SPACE_PIO + && ahd->bshs[0].ioport != 0) + release_region(ahd->bshs[0].ioport, 256); + if (ahd->tags[1] == BUS_SPACE_PIO + && ahd->bshs[1].ioport != 0) + release_region(ahd->bshs[1].ioport, 256); + if (ahd->tags[0] == BUS_SPACE_MEMIO + && ahd->bshs[0].maddr != NULL) { + iounmap(ahd->bshs[0].maddr); + release_mem_region(ahd->platform_data->mem_busaddr, + 0x1000); + } + free(ahd->platform_data, M_DEVBUF); + } } -static void -ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) +void +ahd_platform_init(struct ahd_softc *ahd) { + /* + * Lookup and commit any modified IO Cell options. + */ + if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) { + struct ahd_linux_iocell_opts *iocell_opts; - if ((instance >= 0) && (targ >= 0) - && (instance < NUM_ELEMENTS(aic79xx_tag_info)) - && (targ < AHD_NUM_TARGETS)) { - aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; - if (bootverbose) - printf("tag_info[%d:%d] = %d\n", instance, targ, value); + iocell_opts = &aic79xx_iocell_info[ahd->unit]; + if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP) + AHD_SET_PRECOMP(ahd, iocell_opts->precomp); + if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE) + AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate); + if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE) + AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude); } -} -static void -ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value) -{ - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { - aic79xx_rd_strm_info[instance] = value & 0xFFFF; - if (bootverbose) - printf("rd_strm[%d] = 0x%x\n", instance, value); - } } -static void -ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value) +void +ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) { - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { - aic79xx_dv_settings[instance] = value; - if (bootverbose) - printf("dv[%d] = %d\n", instance, value); - } + ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), + SCB_GET_CHANNEL(ahd, scb), + SCB_GET_LUN(scb), SCB_LIST_NULL, + ROLE_UNKNOWN, CAM_REQUEUE_REQ); } -static void -ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) +void +ahd_platform_set_tags(struct ahd_softc *ahd, 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; - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) { - uint8_t *iocell_info; - - iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; - iocell_info[index] = value & 0xFFFF; - if (bootverbose) - printf("iocell[%d:%ld] = %d\n", instance, index, value); - } -} - -static void -ahd_linux_setup_tag_info_global(char *p) -{ - int tags, i, j; + 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; - tags = simple_strtoul(p + 1, NULL, 0) & 0xff; - printf("Setting Global Tags= %d\n", tags); + dev = scsi_transport_device_data(sdev); - for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) { - for (j = 0; j < AHD_NUM_TARGETS; j++) { - aic79xx_tag_info[i].tag_commands[j] = tags; - } + if (dev == NULL) + return; + was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); + switch (alg) { + default: + case AHD_QUEUE_NONE: + now_queuing = 0; + break; + case AHD_QUEUE_BASIC: + now_queuing = AHD_DEV_Q_BASIC; + break; + case AHD_QUEUE_TAGGED: + now_queuing = AHD_DEV_Q_TAGGED; + break; + } + if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 + && (was_queuing != now_queuing) + && (dev->active != 0)) { + dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY; + dev->qfrozen++; } -} -/* - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic79xx=stpwlev:1,extended - */ -static int -aic79xx_setup(char *s) -{ - int i, n; - char *p; - char *end; + dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG); + if (now_queuing) { + u_int usertags; - static struct { - const char *name; - uint32_t *flag; - } options[] = { - { "extended", &aic79xx_extended }, - { "no_reset", &aic79xx_no_reset }, - { "verbose", &aic79xx_verbose }, - { "allow_memio", &aic79xx_allow_memio}, -#ifdef AHD_DEBUG - { "debug", &ahd_debug }, -#endif - { "reverse_scan", &aic79xx_reverse_scan }, - { "periodic_otag", &aic79xx_periodic_otag }, - { "pci_parity", &aic79xx_pci_parity }, - { "seltime", &aic79xx_seltime }, - { "tag_info", NULL }, - { "global_tag_depth", NULL}, - { "rd_strm", NULL }, - { "dv", NULL }, - { "slewrate", NULL }, - { "precomp", NULL }, - { "amplitude", NULL }, - }; - - end = strchr(s, '\0'); - - /* - * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS - * will never be 0 in this case. - */ - n = 0; - - while ((p = strsep(&s, ",.")) != NULL) { - if (*p == '\0') - continue; - for (i = 0; i < NUM_ELEMENTS(options); i++) { - - n = strlen(options[i].name); - if (strncmp(options[i].name, p, n) == 0) - break; - } - if (i == NUM_ELEMENTS(options)) - continue; - - if (strncmp(p, "global_tag_depth", n) == 0) { - ahd_linux_setup_tag_info_global(p + n); - } else if (strncmp(p, "tag_info", n) == 0) { - s = aic_parse_brace_option("tag_info", p + n, end, - 2, ahd_linux_setup_tag_info, 0); - } else if (strncmp(p, "rd_strm", n) == 0) { - s = aic_parse_brace_option("rd_strm", p + n, end, - 1, ahd_linux_setup_rd_strm_info, 0); - } else if (strncmp(p, "dv", n) == 0) { - s = aic_parse_brace_option("dv", p + n, end, 1, - ahd_linux_setup_dv, 0); - } else if (strncmp(p, "slewrate", n) == 0) { - s = aic_parse_brace_option("slewrate", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_SLEWRATE_INDEX); - } else if (strncmp(p, "precomp", n) == 0) { - s = aic_parse_brace_option("precomp", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_PRECOMP_INDEX); - } else if (strncmp(p, "amplitude", n) == 0) { - s = aic_parse_brace_option("amplitude", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_AMPLITUDE_INDEX); - } else if (p[n] == ':') { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) ^= 0xFFFFFFFF; + usertags = ahd_linux_user_tagdepth(ahd, devinfo); + if (!was_queuing) { + /* + * Start out agressively and allow our + * dynamic queue depth algorithm to take + * care of the rest. + */ + dev->maxtags = usertags; + dev->openings = dev->maxtags - dev->active; } + if (dev->maxtags == 0) { + /* + * Queueing is disabled by the user. + */ + dev->openings = 1; + } else if (alg == AHD_QUEUE_TAGGED) { + dev->flags |= AHD_DEV_Q_TAGGED; + if (aic79xx_periodic_otag != 0) + dev->flags |= AHD_DEV_PERIODIC_OTAG; + } else + dev->flags |= AHD_DEV_Q_BASIC; + } else { + /* We can only have one opening. */ + dev->maxtags = 0; + dev->openings = 1 - dev->active; } - return 1; -} - -__setup("aic79xx=", aic79xx_setup); - -uint32_t aic79xx_verbose; - -int -ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) -{ - char buf[80]; - struct Scsi_Host *host; - char *new_name; - u_long s; - u_long target; - - template->name = ahd->description; - host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); - if (host == NULL) - return (ENOMEM); - - *((struct ahd_softc **)host->hostdata) = ahd; - ahd_lock(ahd, &s); - scsi_assign_lock(host, &ahd->platform_data->spin_lock); - ahd->platform_data->host = host; - host->can_queue = AHD_MAX_QUEUE; - host->cmd_per_lun = 2; - host->sg_tablesize = AHD_NSEG; - host->this_id = ahd->our_id; - host->irq = ahd->platform_data->irq; - host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8; - host->max_lun = AHD_NUM_LUNS; - host->max_channel = 0; - host->sg_tablesize = AHD_NSEG; - ahd_set_unit(ahd, ahd_linux_next_unit()); - sprintf(buf, "scsi%d", host->host_no); - new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); - if (new_name != NULL) { - strcpy(new_name, buf); - ahd_set_name(ahd, new_name); - } - host->unique_id = ahd->unit; - ahd_linux_setup_user_rd_strm_settings(ahd); - ahd_linux_initialize_scsi_bus(ahd); - ahd_unlock(ahd, &s); - ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0); - ahd_lock(ahd, &s); - if (ahd->platform_data->dv_pid < 0) { - printf("%s: Failed to create DV thread, error= %d\n", - ahd_name(ahd), ahd->platform_data->dv_pid); - return (-ahd->platform_data->dv_pid); - } - /* - * Initially allocate *all* of our linux target objects - * so that the DV thread will scan them all in parallel - * just after driver initialization. Any device that - * does not exist will have its target object destroyed - * by the selection timeout handler. In the case of a - * device that appears after the initial DV scan, async - * negotiation will occur for the first command, and DV - * will comence should that first command be successful. - */ - for (target = 0; target < host->max_id; target++) { + switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { + case AHD_DEV_Q_BASIC: + scsi_adjust_queue_depth(sdev, + MSG_SIMPLE_TASK, + dev->openings + dev->active); + break; + case AHD_DEV_Q_TAGGED: + scsi_adjust_queue_depth(sdev, + MSG_ORDERED_TASK, + dev->openings + dev->active); + break; + default: /* - * Skip our own ID. Some Compaq/HP storage devices - * have enclosure management devices that respond to - * single bit selection (i.e. selecting ourselves). - * It is expected that either an external application - * or a modified kernel will be used to probe this - * ID if it is appropriate. To accommodate these - * installations, ahc_linux_alloc_target() will allocate - * for our ID if asked to do so. + * We allow the OS to queue 2 untagged transactions to + * us at any time even though we can only execute them + * serially on the controller/device. This should + * remove some latency. */ - if (target == ahd->our_id) - continue; - - ahd_linux_alloc_target(ahd, 0, target); + scsi_adjust_queue_depth(sdev, + /*NON-TAGGED*/0, + /*queue depth*/2); + break; } - ahd_intr_enable(ahd, TRUE); - ahd_linux_start_dv(ahd); - ahd_unlock(ahd, &s); - - scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ - scsi_scan_host(host); - return (0); } -uint64_t -ahd_linux_get_memsize(void) +int +ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, + int lun, u_int tag, role_t role, uint32_t status) { - struct sysinfo si; - - si_meminfo(&si); - return ((uint64_t)si.totalram << PAGE_SHIFT); + return 0; } -/* - * Find the smallest available unit number to use - * for a new device. We don't just use a static - * count to handle the "repeated hot-(un)plug" - * scenario. - */ -static int -ahd_linux_next_unit(void) +static u_int +ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { - struct ahd_softc *ahd; - int unit; + static int warned_user; + u_int tags; - unit = 0; -retry: - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->unit == unit) { - unit++; - goto retry; + tags = 0; + if ((ahd->user_discenable & devinfo->target_mask) != 0) { + if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { + + if (warned_user == 0) { + printf(KERN_WARNING +"aic79xx: WARNING: Insufficient tag_info instances\n" +"aic79xx: for installed controllers. Using defaults\n" +"aic79xx: Please update the aic79xx_tag_info array in\n" +"aic79xx: the aic79xx_osm.c source file.\n"); + warned_user++; + } + tags = AHD_MAX_QUEUE; + } else { + adapter_tag_info_t *tag_info; + + tag_info = &aic79xx_tag_info[ahd->unit]; + tags = tag_info->tag_commands[devinfo->target_offset]; + if (tags > AHD_MAX_QUEUE) + tags = AHD_MAX_QUEUE; } } - return (unit); + return (tags); } /* - * Place the SCSI bus into a known state by either resetting it, - * or forcing transfer negotiations on the next command to any - * target. + * Determines the queue depth for a given device. */ static void -ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) +ahd_linux_device_queue_depth(struct scsi_device *sdev) { - u_int target_id; - u_int numtarg; + struct ahd_devinfo devinfo; + u_int tags; + struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); - target_id = 0; - numtarg = 0; + ahd_compile_devinfo(&devinfo, + ahd->our_id, + sdev->sdev_target->id, sdev->lun, + sdev->sdev_target->channel == 0 ? 'A' : 'B', + ROLE_INITIATOR); + tags = ahd_linux_user_tagdepth(ahd, &devinfo); + if (tags != 0 && sdev->tagged_supported != 0) { - if (aic79xx_no_reset != 0) - ahd->flags &= ~AHD_RESET_BUS_A; + ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); + ahd_print_devinfo(ahd, &devinfo); + printf("Tagged Queuing enabled. Depth %d\n", tags); + } else { + ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); + } +} - if ((ahd->flags & AHD_RESET_BUS_A) != 0) - ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE); - else - numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; +static int +ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, + struct scsi_cmnd *cmd) +{ + struct scb *scb; + struct hardware_scb *hscb; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; + u_int col_idx; + uint16_t mask; /* - * Force negotiation to async for all targets that - * will not see an initial bus reset. + * Get an scb to use. */ - for (; target_id < numtarg; target_id++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - target_id, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, - CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); - ahd_update_neg_request(ahd, &devinfo, tstate, - tinfo, AHD_NEG_ALWAYS); - } - /* Give the bus some time to recover */ - if ((ahd->flags & AHD_RESET_BUS_A) != 0) { - ahd_freeze_simq(ahd); - init_timer(&ahd->platform_data->reset_timer); - ahd->platform_data->reset_timer.data = (u_long)ahd; - ahd->platform_data->reset_timer.expires = - jiffies + (AIC79XX_RESET_DELAY * HZ)/1000; - ahd->platform_data->reset_timer.function = - (ahd_linux_callback_t *)ahd_release_simq; - add_timer(&ahd->platform_data->reset_timer); + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + cmd->device->id, &tstate); + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 + || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { + col_idx = AHD_NEVER_COL_IDX; + } else { + col_idx = AHD_BUILD_COL_IDX(cmd->device->id, + cmd->device->lun); + } + if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { + ahd->flags |= AHD_RESOURCE_SHORTAGE; + return SCSI_MLQUEUE_HOST_BUSY; } -} -int -ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) -{ - ahd->platform_data = - malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT); - if (ahd->platform_data == NULL) - return (ENOMEM); - memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); - TAILQ_INIT(&ahd->platform_data->completeq); - ahd->platform_data->irq = AHD_LINUX_NOIRQ; - ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; - ahd_lockinit(ahd); - ahd_done_lockinit(ahd); - init_timer(&ahd->platform_data->completeq_timer); - ahd->platform_data->completeq_timer.data = (u_long)ahd; - ahd->platform_data->completeq_timer.function = - (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue; - init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); - init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); - init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); - ahd->seltime = (aic79xx_seltime & 0x3) << 4; - return (0); -} + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; -void -ahd_platform_free(struct ahd_softc *ahd) -{ - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; - int i, j; + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahd, cmd); + hscb->lun = cmd->device->lun; + scb->hscb->task_management = 0; + mask = SCB_GET_TARGET_MASK(ahd, scb); - if (ahd->platform_data != NULL) { - del_timer_sync(&ahd->platform_data->completeq_timer); - ahd_linux_kill_dv_thread(ahd); - if (ahd->platform_data->host != NULL) { - scsi_remove_host(ahd->platform_data->host); - scsi_host_put(ahd->platform_data->host); - } + if ((ahd->user_discenable & mask) != 0) + hscb->control |= DISCENB; - /* destroy all of the device and target objects */ - for (i = 0; i < AHD_NUM_TARGETS; i++) { - targ = ahd->platform_data->targets[i]; - if (targ != NULL) { - /* Keep target around through the loop. */ - targ->refcount++; - for (j = 0; j < AHD_NUM_LUNS; j++) { + if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) + scb->flags |= SCB_PACKETIZED; - if (targ->devices[j] == NULL) - continue; - dev = targ->devices[j]; - ahd_linux_free_device(ahd, dev); - } - /* - * Forcibly free the target now that - * all devices are gone. - */ - ahd_linux_free_target(ahd, targ); - } + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { + int msg_bytes; + uint8_t tag_msgs[2]; + + msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); + if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { + hscb->control |= tag_msgs[0]; + if (tag_msgs[0] == MSG_ORDERED_TASK) + dev->commands_since_idle_or_otag = 0; + } else + if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH + && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; } + } - if (ahd->platform_data->irq != AHD_LINUX_NOIRQ) - free_irq(ahd->platform_data->irq, ahd); - if (ahd->tags[0] == BUS_SPACE_PIO - && ahd->bshs[0].ioport != 0) - release_region(ahd->bshs[0].ioport, 256); - if (ahd->tags[1] == BUS_SPACE_PIO - && ahd->bshs[1].ioport != 0) - release_region(ahd->bshs[1].ioport, 256); - if (ahd->tags[0] == BUS_SPACE_MEMIO - && ahd->bshs[0].maddr != NULL) { - iounmap(ahd->bshs[0].maddr); - release_mem_region(ahd->platform_data->mem_busaddr, - 0x1000); + hscb->cdb_len = cmd->cmd_len; + memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); + + scb->platform_data->xfer_len = 0; + ahd_set_residual(scb, 0); + ahd_set_sense_residual(scb, 0); + scb->sg_count = 0; + if (cmd->use_sg != 0) { + void *sg; + struct scatterlist *cur_seg; + u_int nseg; + int dir; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + dir = cmd->sc_data_direction; + nseg = pci_map_sg(ahd->dev_softc, cur_seg, + cmd->use_sg, dir); + scb->platform_data->xfer_len = 0; + for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { + dma_addr_t addr; + bus_size_t len; + + addr = sg_dma_address(cur_seg); + len = sg_dma_len(cur_seg); + scb->platform_data->xfer_len += len; + sg = ahd_sg_setup(ahd, scb, sg, addr, len, + /*last*/nseg == 1); } - free(ahd->platform_data, M_DEVBUF); + } else if (cmd->request_bufflen != 0) { + void *sg; + dma_addr_t addr; + int dir; + + sg = scb->sg_list; + dir = cmd->sc_data_direction; + addr = pci_map_single(ahd->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, dir); + scb->platform_data->xfer_len = cmd->request_bufflen; + scb->platform_data->buf_busaddr = addr; + sg = ahd_sg_setup(ahd, scb, sg, addr, + cmd->request_bufflen, /*last*/TRUE); } + + LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->commands_issued++; + + if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) + dev->commands_since_idle_or_otag++; + scb->flags |= SCB_ACTIVE; + ahd_queue_scb(ahd, scb); + + return 0; } -void -ahd_platform_init(struct ahd_softc *ahd) +/* + * SCSI controller interrupt handler. + */ +irqreturn_t +ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { - /* - * Lookup and commit any modified IO Cell options. - */ - if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) { - struct ahd_linux_iocell_opts *iocell_opts; - - iocell_opts = &aic79xx_iocell_info[ahd->unit]; - if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP) - AHD_SET_PRECOMP(ahd, iocell_opts->precomp); - if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE) - AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate); - if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE) - AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude); - } + struct ahd_softc *ahd; + u_long flags; + int ours; + ahd = (struct ahd_softc *) dev_id; + ahd_lock(ahd, &flags); + ours = ahd_intr(ahd); + ahd_unlock(ahd, &flags); + return IRQ_RETVAL(ours); } void -ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) +ahd_platform_flushwork(struct ahd_softc *ahd) { - ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_REQUEUE_REQ); + } void -ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - ahd_queue_alg alg) +ahd_send_async(struct ahd_softc *ahd, char channel, + u_int target, u_int lun, ac_code code, void *arg) { - struct ahd_linux_device *dev; - int was_queuing; - int now_queuing; + switch (code) { + case AC_TRANSFER_NEG: + { + char buf[80]; + struct scsi_target *starget; + struct ahd_linux_target *targ; + struct info_str info; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; + unsigned int target_ppr_options; - dev = ahd_linux_get_device(ahd, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); - if (dev == NULL) - return; - was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); - switch (alg) { - default: - case AHD_QUEUE_NONE: - now_queuing = 0; - break; - case AHD_QUEUE_BASIC: - now_queuing = AHD_DEV_Q_BASIC; + BUG_ON(target == CAM_TARGET_WILDCARD); + + info.buffer = buf; + info.length = sizeof(buf); + info.offset = 0; + info.pos = 0; + tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, + target, &tstate); + + /* + * Don't bother reporting results while + * negotiations are still pending. + */ + if (tinfo->curr.period != tinfo->goal.period + || tinfo->curr.width != tinfo->goal.width + || tinfo->curr.offset != tinfo->goal.offset + || tinfo->curr.ppr_options != tinfo->goal.ppr_options) + if (bootverbose == 0) + break; + + /* + * Don't bother reporting results that + * are identical to those last reported. + */ + starget = ahd->platform_data->starget[target]; + targ = scsi_transport_target_data(starget); + if (targ == NULL) + break; + + target_ppr_options = + (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) + + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) + + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0); + + if (tinfo->curr.period == spi_period(starget) + && tinfo->curr.width == spi_width(starget) + && tinfo->curr.offset == spi_offset(starget) + && tinfo->curr.ppr_options == target_ppr_options) + if (bootverbose == 0) + break; + + spi_period(starget) = tinfo->curr.period; + spi_width(starget) = tinfo->curr.width; + spi_offset(starget) = tinfo->curr.offset; + spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ; + spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ; + spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ; + spi_display_xfer_agreement(starget); break; - case AHD_QUEUE_TAGGED: - now_queuing = AHD_DEV_Q_TAGGED; + } + case AC_SENT_BDR: + { + WARN_ON(lun != CAM_LUN_WILDCARD); + scsi_report_device_reset(ahd->platform_data->host, + channel - 'A', target); break; } - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 - && (was_queuing != now_queuing) - && (dev->active != 0)) { - dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen++; - } - - dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG); - if (now_queuing) { - u_int usertags; - - usertags = ahd_linux_user_tagdepth(ahd, devinfo); - if (!was_queuing) { - /* - * Start out agressively and allow our - * dynamic queue depth algorithm to take - * care of the rest. - */ - dev->maxtags = usertags; - dev->openings = dev->maxtags - dev->active; - } - if (dev->maxtags == 0) { - /* - * Queueing is disabled by the user. - */ - dev->openings = 1; - } else if (alg == AHD_QUEUE_TAGGED) { - dev->flags |= AHD_DEV_Q_TAGGED; - if (aic79xx_periodic_otag != 0) - dev->flags |= AHD_DEV_PERIODIC_OTAG; - } else - dev->flags |= AHD_DEV_Q_BASIC; - } else { - /* We can only have one opening. */ - dev->maxtags = 0; - dev->openings = 1 - dev->active; - } - - if (dev->scsi_device != NULL) { - switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { - case AHD_DEV_Q_BASIC: - scsi_adjust_queue_depth(dev->scsi_device, - MSG_SIMPLE_TASK, - dev->openings + dev->active); - break; - case AHD_DEV_Q_TAGGED: - scsi_adjust_queue_depth(dev->scsi_device, - MSG_ORDERED_TASK, - dev->openings + dev->active); - break; - default: - /* - * We allow the OS to queue 2 untagged transactions to - * us at any time even though we can only execute them - * serially on the controller/device. This should - * remove some latency. - */ - scsi_adjust_queue_depth(dev->scsi_device, - /*NON-TAGGED*/0, - /*queue depth*/2); - break; + case AC_BUS_RESET: + if (ahd->platform_data->host != NULL) { + scsi_report_bus_reset(ahd->platform_data->host, + channel - 'A'); } - } -} - -int -ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - return 0; -} - -static void -ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd) -{ - u_long flags; - - ahd_lock(ahd, &flags); - del_timer(&ahd->platform_data->completeq_timer); - ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER; - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &flags); + break; + default: + panic("ahd_send_async: Unexpected async event"); + } } -static void -ahd_linux_start_dv(struct ahd_softc *ahd) +/* + * Calls the higher level scsi done function and frees the scb. + */ +void +ahd_done(struct ahd_softc *ahd, struct scb *scb) { + struct scsi_cmnd *cmd; + struct ahd_linux_device *dev; - /* - * Freeze the simq and signal ahd_linux_queue to not let any - * more commands through - */ - if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s: Starting DV\n", ahd_name(ahd)); -#endif - - ahd->platform_data->flags |= AHD_DV_ACTIVE; - ahd_freeze_simq(ahd); - - /* Wake up the DV kthread */ - up(&ahd->platform_data->dv_sem); + if ((scb->flags & SCB_ACTIVE) == 0) { + printf("SCB %d done'd twice\n", SCB_GET_TAG(scb)); + ahd_dump_card_state(ahd); + panic("Stopping for safety"); } -} - -static int -ahd_linux_dv_thread(void *data) -{ - struct ahd_softc *ahd; - int target; - u_long s; - - ahd = (struct ahd_softc *)data; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("In DV Thread\n"); -#endif + LIST_REMOVE(scb, pending_links); + cmd = scb->io_ctx; + dev = scb->platform_data->dev; + dev->active--; + dev->openings++; + if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { + cmd->result &= ~(CAM_DEV_QFRZN << 16); + dev->qfrozen--; + } + ahd_linux_unmap_scb(ahd, scb); /* - * Complete thread creation. + * Guard against stale sense data. + * The Linux mid-layer assumes that sense + * was retrieved anytime the first byte of + * the sense buffer looks "sane". */ - lock_kernel(); - - daemonize("ahd_dv_%d", ahd->unit); - current->flags |= PF_FREEZE; - - unlock_kernel(); - - while (1) { - /* - * Use down_interruptible() rather than down() to - * avoid inclusion in the load average. - */ - down_interruptible(&ahd->platform_data->dv_sem); - - /* Check to see if we've been signaled to exit */ - ahd_lock(ahd, &s); - if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) { - ahd_unlock(ahd, &s); - break; - } - ahd_unlock(ahd, &s); + cmd->sense_buffer[0] = 0; + if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) { + uint32_t amount_xferred; + amount_xferred = + ahd_get_transfer_length(scb) - ahd_get_residual(scb); + if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { #ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s: Beginning Domain Validation\n", - ahd_name(ahd)); + if ((ahd_debug & AHD_SHOW_MISC) != 0) { + ahd_print_path(ahd, scb); + printf("Set CAM_UNCOR_PARITY\n"); + } #endif - + ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); +#ifdef AHD_REPORT_UNDERFLOWS /* - * Wait for any pending commands to drain before proceeding. + * This code is disabled by default as some + * clients of the SCSI system do not properly + * initialize the underflow parameter. This + * results in spurious termination of commands + * that complete as expected (e.g. underflow is + * allowed as command can return variable amounts + * of data. */ - ahd_lock(ahd, &s); - while (LIST_FIRST(&ahd->pending_scbs) != NULL) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); - } + } else if (amount_xferred < scb->io_ctx->underflow) { + u_int i; - /* - * Wait for the SIMQ to be released so that DV is the - * only reason the queue is frozen. - */ - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); + ahd_print_path(ahd, scb); + printf("CDB:"); + for (i = 0; i < scb->io_ctx->cmd_len; i++) + printf(" 0x%x", scb->io_ctx->cmnd[i]); + printf("\n"); + ahd_print_path(ahd, scb); + printf("Saw underflow (%ld of %ld bytes). " + "Treated as error\n", + ahd_get_residual(scb), + ahd_get_transfer_length(scb)); + ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); +#endif + } else { + ahd_set_transaction_status(scb, CAM_REQ_CMP); } - ahd_unlock(ahd, &s); + } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { + ahd_linux_handle_scsi_status(ahd, cmd->device, scb); + } - for (target = 0; target < AHD_NUM_TARGETS; target++) - ahd_linux_dv_target(ahd, target); + if (dev->openings == 1 + && ahd_get_transaction_status(scb) == CAM_REQ_CMP + && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) + dev->tag_success_count++; + /* + * Some devices deal with temporary internal resource + * shortages by returning queue full. When the queue + * full occurrs, we throttle back. Slowly try to get + * back to our previous queue depth. + */ + if ((dev->openings + dev->active) < dev->maxtags + && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) { + dev->tag_success_count = 0; + dev->openings++; + } - ahd_lock(ahd, &s); - ahd->platform_data->flags &= ~AHD_DV_ACTIVE; - ahd_unlock(ahd, &s); + if (dev->active == 0) + dev->commands_since_idle_or_otag = 0; - /* - * Release the SIMQ so that normal commands are - * allowed to continue on the bus. - */ - ahd_release_simq(ahd); + if ((scb->flags & SCB_RECOVERY_SCB) != 0) { + printf("Recovery SCB completes\n"); + if (ahd_get_transaction_status(scb) == CAM_BDR_SENT + || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) + ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); + if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + up(&ahd->platform_data->eh_sem); + } } - up(&ahd->platform_data->eh_sem); - return (0); + + ahd_free_scb(ahd, scb); + ahd_linux_queue_cmd_complete(ahd, cmd); } static void -ahd_linux_kill_dv_thread(struct ahd_softc *ahd) +ahd_linux_handle_scsi_status(struct ahd_softc *ahd, + struct scsi_device *sdev, struct scb *scb) { - u_long s; - - ahd_lock(ahd, &s); - if (ahd->platform_data->dv_pid != 0) { - ahd->platform_data->flags |= AHD_DV_SHUTDOWN; - ahd_unlock(ahd, &s); - up(&ahd->platform_data->dv_sem); + struct ahd_devinfo devinfo; + struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - /* - * Use the eh_sem as an indicator that the - * dv thread is exiting. Note that the dv - * thread must still return after performing - * the up on our semaphore before it has - * completely exited this module. Unfortunately, - * there seems to be no easy way to wait for the - * exit of a thread for which you are not the - * parent (dv threads are parented by init). - * Cross your fingers... - */ - down(&ahd->platform_data->eh_sem); + ahd_compile_devinfo(&devinfo, + ahd->our_id, + sdev->sdev_target->id, sdev->lun, + sdev->sdev_target->channel == 0 ? 'A' : 'B', + ROLE_INITIATOR); + + /* + * We don't currently trust the mid-layer to + * properly deal with queue full or busy. So, + * when one occurs, we tell the mid-layer to + * unconditionally requeue the command to us + * so that we can retry it ourselves. We also + * implement our own throttling mechanism so + * we don't clobber the device with too many + * commands. + */ + switch (ahd_get_scsi_status(scb)) { + default: + break; + case SCSI_STATUS_CHECK_COND: + case SCSI_STATUS_CMD_TERMINATED: + { + struct scsi_cmnd *cmd; /* - * Mark the dv thread as already dead. This - * avoids attempting to kill it a second time. - * This is necessary because we must kill the - * DV thread before calling ahd_free() in the - * module shutdown case to avoid bogus locking - * in the SCSI mid-layer, but we ahd_free() is - * called without killing the DV thread in the - * instance detach case, so ahd_platform_free() - * calls us again to verify that the DV thread - * is dead. + * Copy sense information to the OS's cmd + * structure if it is available. */ - ahd->platform_data->dv_pid = 0; - } else { - ahd_unlock(ahd, &s); - } -} - -#define AHD_LINUX_DV_INQ_SHORT_LEN 36 -#define AHD_LINUX_DV_INQ_LEN 256 -#define AHD_LINUX_DV_TIMEOUT (HZ / 4) + cmd = scb->io_ctx; + if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) { + struct scsi_status_iu_header *siu; + u_int sense_size; + u_int sense_offset; -#define AHD_SET_DV_STATE(ahd, targ, newstate) \ - ahd_set_dv_state(ahd, targ, newstate, __LINE__) + if (scb->flags & SCB_SENSE) { + sense_size = MIN(sizeof(struct scsi_sense_data) + - ahd_get_sense_residual(scb), + sizeof(cmd->sense_buffer)); + sense_offset = 0; + } else { + /* + * Copy only the sense data into the provided + * buffer. + */ + siu = (struct scsi_status_iu_header *) + scb->sense_data; + sense_size = MIN(scsi_4btoul(siu->sense_length), + sizeof(cmd->sense_buffer)); + sense_offset = SIU_SENSE_OFFSET(siu); + } -static __inline void -ahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ, - ahd_dv_state newstate, u_int line) -{ - ahd_dv_state oldstate; + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + memcpy(cmd->sense_buffer, + ahd_get_sense_buf(ahd, scb) + + sense_offset, sense_size); + cmd->result |= (DRIVER_SENSE << 24); - oldstate = targ->dv_state; #ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s:%d: Going from state %d to state %d\n", - ahd_name(ahd), line, oldstate, newstate); -#endif - - if (oldstate == newstate) - targ->dv_state_retry++; - else - targ->dv_state_retry = 0; - targ->dv_state = newstate; -} + if (ahd_debug & AHD_SHOW_SENSE) { + int i; -static void -ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) -{ - struct ahd_devinfo devinfo; - struct ahd_linux_target *targ; - struct scsi_cmnd *cmd; - struct scsi_device *scsi_dev; - struct scsi_sense_data *sense; - uint8_t *buffer; - u_long s; - u_int timeout; - int echo_size; - - sense = NULL; - buffer = NULL; - echo_size = 0; - ahd_lock(ahd, &s); - targ = ahd->platform_data->targets[target_offset]; - if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) { - ahd_unlock(ahd, &s); - return; - } - ahd_compile_devinfo(&devinfo, ahd->our_id, targ->target, /*lun*/0, - targ->channel + 'A', ROLE_INITIATOR); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, &devinfo); - printf("Performing DV\n"); - } -#endif - - ahd_unlock(ahd, &s); - - cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK); - scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK); - scsi_dev->host = ahd->platform_data->host; - scsi_dev->id = devinfo.target; - scsi_dev->lun = devinfo.lun; - scsi_dev->channel = devinfo.channel - 'A'; - ahd->platform_data->dv_scsi_dev = scsi_dev; - - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC); - - while (targ->dv_state != AHD_DV_STATE_EXIT) { - timeout = AHD_LINUX_DV_TIMEOUT; - switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: - case AHD_DV_STATE_INQ_ASYNC_VERIFY: - /* - * Set things to async narrow to reduce the - * chance that the INQ will fail. - */ - ahd_lock(ahd, &s); - ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_unlock(ahd, &s); - timeout = 10 * HZ; - targ->flags &= ~AHD_INQ_VALID; - /* FALLTHROUGH */ - case AHD_DV_STATE_INQ_VERIFY: - { - u_int inq_len; - - if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC) - inq_len = AHD_LINUX_DV_INQ_SHORT_LEN; - else - inq_len = targ->inq_data->additional_length + 5; - ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len); - break; - } - case AHD_DV_STATE_TUR: - case AHD_DV_STATE_BUSY: - timeout = 5 * HZ; - ahd_linux_dv_tur(ahd, cmd, &devinfo); - break; - case AHD_DV_STATE_REBD: - ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ); - break; - case AHD_DV_STATE_WEB: - ahd_linux_dv_web(ahd, cmd, &devinfo, targ); - break; - - case AHD_DV_STATE_REB: - ahd_linux_dv_reb(ahd, cmd, &devinfo, targ); - break; - - case AHD_DV_STATE_SU: - ahd_linux_dv_su(ahd, cmd, &devinfo, targ); - timeout = 50 * HZ; - break; - - default: - ahd_print_devinfo(ahd, &devinfo); - printf("Unknown DV state %d\n", targ->dv_state); - goto out; - } - - /* Queue the command and wait for it to complete */ - /* Abuse eh_timeout in the scsi_cmnd struct for our purposes */ - init_timer(&cmd->eh_timeout); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - /* - * All of the printfs during negotiation - * really slow down the negotiation. - * Add a bit of time just to be safe. - */ - timeout += HZ; -#endif - scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout); - /* - * In 2.5.X, it is assumed that all calls from the - * "midlayer" (which we are emulating) will have the - * ahd host lock held. For other kernels, the - * io_request_lock must be held. - */ -#if AHD_SCSI_HAS_HOST_LOCK != 0 - ahd_lock(ahd, &s); -#else - spin_lock_irqsave(&io_request_lock, s); -#endif - ahd_linux_queue(cmd, ahd_linux_dv_complete); -#if AHD_SCSI_HAS_HOST_LOCK != 0 - ahd_unlock(ahd, &s); -#else - spin_unlock_irqrestore(&io_request_lock, s); -#endif - down_interruptible(&ahd->platform_data->dv_cmd_sem); - /* - * Wait for the SIMQ to be released so that DV is the - * only reason the queue is frozen. - */ - ahd_lock(ahd, &s); - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); - } - ahd_unlock(ahd, &s); - - ahd_linux_dv_transition(ahd, cmd, &devinfo, targ); - } - -out: - if ((targ->flags & AHD_INQ_VALID) != 0 - && ahd_linux_get_device(ahd, devinfo.channel - 'A', - devinfo.target, devinfo.lun, - /*alloc*/FALSE) == NULL) { - /* - * The DV state machine failed to configure this device. - * This is normal if DV is disabled. Since we have inquiry - * data, filter it and use the "optimistic" negotiation - * parameters found in the inquiry string. - */ - ahd_linux_filter_inquiry(ahd, &devinfo); - if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) { - ahd_print_devinfo(ahd, &devinfo); - printf("DV failed to configure device. " - "Please file a bug report against " - "this driver.\n"); - } - } - - if (cmd != NULL) - free(cmd, M_DEVBUF); - - if (ahd->platform_data->dv_scsi_dev != NULL) { - free(ahd->platform_data->dv_scsi_dev, M_DEVBUF); - ahd->platform_data->dv_scsi_dev = NULL; - } - - ahd_lock(ahd, &s); - if (targ->dv_buffer != NULL) { - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = NULL; - } - if (targ->dv_buffer1 != NULL) { - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = NULL; - } - targ->flags &= ~AHD_DV_REQUIRED; - if (targ->refcount == 0) - ahd_linux_free_target(ahd, targ); - ahd_unlock(ahd, &s); -} - -static __inline int -ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_long s; - int retval; - - ahd_lock(ahd, &s); - retval = ahd_linux_fallback(ahd, devinfo); - ahd_unlock(ahd, &s); - - return (retval); -} - -static void -ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) -{ - u_int32_t status; - - status = aic_error_action(cmd, targ->inq_data, - ahd_cmd_get_transaction_status(cmd), - ahd_cmd_get_scsi_status(cmd)); - - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Entering ahd_linux_dv_transition, state= %d, " - "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state, - status, cmd->result); - } -#endif - - switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: - switch (status & SS_MASK) { - case SS_NOP: - { - AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - case AHD_DV_STATE_INQ_ASYNC_VERIFY: - switch (status & SS_MASK) { - case SS_NOP: - { - u_int xportflags; - u_int spi3data; - - if (memcmp(targ->inq_data, targ->dv_buffer, - AHD_LINUX_DV_INQ_LEN) != 0) { - /* - * Inquiry data must have changed. - * Try from the top again. - */ - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - } - - AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1); - targ->flags |= AHD_INQ_VALID; - if (ahd_linux_user_dv_setting(ahd) == 0) - break; - - xportflags = targ->inq_data->flags; - if ((xportflags & (SID_Sync|SID_WBus16)) == 0) - break; - - spi3data = targ->inq_data->spi3data; - switch (spi3data & SID_SPI_CLOCK_DT_ST) { - default: - case SID_SPI_CLOCK_ST: - /* Assume only basic DV is supported. */ - targ->flags |= AHD_BASIC_DV; - break; - case SID_SPI_CLOCK_DT: - case SID_SPI_CLOCK_DT_ST: - targ->flags |= AHD_ENHANCED_DV; - break; - } - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - - if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - case AHD_DV_STATE_INQ_VERIFY: - switch (status & SS_MASK) { - case SS_NOP: - { - - if (memcmp(targ->inq_data, targ->dv_buffer, - AHD_LINUX_DV_INQ_LEN) == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - int i; - - ahd_print_devinfo(ahd, devinfo); - printf("Inquiry buffer mismatch:"); - for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) { + printf("Copied %d bytes of sense data at %d:", + sense_size, sense_offset); + for (i = 0; i < sense_size; i++) { if ((i & 0xF) == 0) - printf("\n "); - printf("0x%x:0x0%x ", - ((uint8_t *)targ->inq_data)[i], - targ->dv_buffer[i]); + printf("\n"); + printf("0x%x ", cmd->sense_buffer[i]); } printf("\n"); } #endif - - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - } else if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - - case AHD_DV_STATE_TUR: - switch (status & SS_MASK) { - case SS_NOP: - if ((targ->flags & AHD_BASIC_DV) != 0) { - ahd_linux_filter_inquiry(ahd, devinfo); - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_VERIFY); - } else if ((targ->flags & AHD_ENHANCED_DV) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD); - } else { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - } - break; - case SS_RETRY: - case SS_TUR: - if ((status & SS_ERRMASK) == EBUSY) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - break; - } - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - } - if (targ->dv_state_retry >= 10) { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV TUR reties exhausted\n"); - } -#endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - if (status & SSQ_DELAY) - ssleep(1); - - break; - case SS_START: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; } break; - - case AHD_DV_STATE_REBD: - switch (status & SS_MASK) { - case SS_NOP: - { - uint32_t echo_size; - - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); - echo_size = scsi_3btoul(&targ->dv_buffer[1]); - echo_size &= 0x1FFF; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Echo buffer size= %d\n", echo_size); - } -#endif - if (echo_size == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - - /* Generate the buffer pattern */ - targ->dv_echo_size = echo_size; - ahd_linux_generate_dv_pattern(targ); + } + case SCSI_STATUS_QUEUE_FULL: + /* + * By the time the core driver has returned this + * command, all other commands that were queued + * to us but not the device have been returned. + * This ensures that dev->active is equal to + * the number of commands actually queued to + * the device. + */ + dev->tag_success_count = 0; + if (dev->active != 0) { /* - * Setup initial negotiation values. + * Drop our opening count to the number + * of commands currently outstanding. */ - ahd_linux_filter_inquiry(ahd, devinfo); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - if (targ->dv_state_retry <= 10) - break; + dev->openings = 0; #ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV REBD reties exhausted\n"); + if ((ahd_debug & AHD_SHOW_QFULL) != 0) { + ahd_print_path(ahd, scb); + printf("Dropping tag count to %d\n", + dev->active); } #endif - /* FALLTHROUGH */ - case SS_FATAL: - default: - /* - * Setup initial negotiation values - * and try level 1 DV. - */ - ahd_linux_filter_inquiry(ahd, devinfo); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY); - targ->dv_echo_size = 0; - break; - } - break; + if (dev->active == dev->tags_on_last_queuefull) { - case AHD_DV_STATE_WEB: - switch (status & SS_MASK) { - case SS_NOP: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } + dev->last_queuefull_same_count++; /* - * Do not count "falling back" - * against our retries. + * If we repeatedly see a queue full + * at the same queue depth, this + * device has a fixed number of tag + * slots. Lock in this tag depth + * so we stop seeing queue fulls from + * this device. */ - targ->dv_state_retry = 0; - } - if (targ->dv_state_retry <= 10) - break; - /* FALLTHROUGH */ -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV WEB reties exhausted\n"); - } -#endif - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_REB: - switch (status & SS_MASK) { - case SS_NOP: - if (memcmp(targ->dv_buffer, targ->dv_buffer1, - targ->dv_echo_size) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - else - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_WEB); - break; - } - - if (targ->dv_buffer != NULL) { - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = NULL; - } - if (targ->dv_buffer1 != NULL) { - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = NULL; - } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; + if (dev->last_queuefull_same_count + == AHD_LOCK_TAGS_COUNT) { + dev->maxtags = dev->active; + ahd_print_path(ahd, scb); + printf("Locking max tag count at %d\n", + dev->active); } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); - } - if (targ->dv_state_retry <= 10) { - if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - msleep(ahd->our_id*1000/10); - break; - } -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV REB reties exhausted\n"); + } else { + dev->tags_on_last_queuefull = dev->active; + dev->last_queuefull_same_count = 0; } -#endif - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_SU: - switch (status & SS_MASK) { - case SS_NOP: - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); + ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); + ahd_set_scsi_status(scb, SCSI_STATUS_OK); + ahd_platform_set_tags(ahd, &devinfo, + (dev->flags & AHD_DEV_Q_BASIC) + ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); break; } - break; - - case AHD_DV_STATE_BUSY: - switch (status & SS_MASK) { - case SS_NOP: - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if (targ->dv_state_retry < 60) { - if ((status & SSQ_DELAY) != 0) - ssleep(1); - } else { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV BUSY reties exhausted\n"); - } -#endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - } - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - default: - printf("%s: Invalid DV completion state %d\n", ahd_name(ahd), - targ->dv_state); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } -} - -static void -ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo) -{ - memset(cmd, 0, sizeof(struct scsi_cmnd)); - cmd->device = ahd->platform_data->dv_scsi_dev; - cmd->scsi_done = ahd_linux_dv_complete; -} - -/* - * Synthesize an inquiry command. On the return trip, it'll be - * sniffed and the device transfer settings set for us. - */ -static void -ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ, - u_int request_length) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending INQ\n"); - } -#endif - if (targ->inq_data == NULL) - targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN, - M_DEVBUF, M_WAITOK); - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) { - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN, - M_DEVBUF, M_WAITOK); - } - - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 6; - cmd->cmnd[0] = INQUIRY; - cmd->cmnd[4] = request_length; - cmd->request_bufflen = request_length; - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) - cmd->request_buffer = targ->dv_buffer; - else - cmd->request_buffer = targ->inq_data; - memset(cmd->request_buffer, 0, AHD_LINUX_DV_INQ_LEN); -} - -static void -ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending TUR\n"); - } -#endif - /* Do a TUR to clear out any non-fatal transitional state */ - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_NONE; - cmd->cmd_len = 6; - cmd->cmnd[0] = TEST_UNIT_READY; -} - -#define AHD_REBD_LEN 4 - -static void -ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending REBD\n"); - } -#endif - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK); - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = READ_BUFFER; - cmd->cmnd[1] = 0x0b; - scsi_ulto3b(AHD_REBD_LEN, &cmd->cmnd[6]); - cmd->request_bufflen = AHD_REBD_LEN; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer; -} - -static void -ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending WEB\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_TO_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = WRITE_BUFFER; - cmd->cmnd[1] = 0x0a; - scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]); - cmd->request_bufflen = targ->dv_echo_size; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer; -} - -static void -ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending REB\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = READ_BUFFER; - cmd->cmnd[1] = 0x0a; - scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]); - cmd->request_bufflen = targ->dv_echo_size; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer1; -} - -static void -ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) -{ - u_int le; - - le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending SU\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_NONE; - cmd->cmd_len = 6; - cmd->cmnd[0] = START_STOP_UNIT; - cmd->cmnd[4] = le | SSS_START; -} - -static int -ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - struct ahd_linux_target *targ; - struct ahd_initiator_tinfo *tinfo; - struct ahd_transinfo *goal; - struct ahd_tmode_tstate *tstate; - u_int width; - u_int period; - u_int offset; - u_int ppr_options; - u_int cur_speed; - u_int wide_speed; - u_int narrow_speed; - u_int fallback_speed; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Trying to fallback\n"); - } -#endif - targ = ahd->platform_data->targets[devinfo->target_offset]; - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - goal = &tinfo->goal; - width = goal->width; - period = goal->period; - offset = goal->offset; - ppr_options = goal->ppr_options; - if (offset == 0) - period = AHD_ASYNC_XFER_PERIOD; - if (targ->dv_next_narrow_period == 0) - targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2); - if (targ->dv_next_wide_period == 0) - targ->dv_next_wide_period = period; - if (targ->dv_max_width == 0) - targ->dv_max_width = width; - if (targ->dv_max_ppr_options == 0) - targ->dv_max_ppr_options = ppr_options; - if (targ->dv_last_ppr_options == 0) - targ->dv_last_ppr_options = ppr_options; - - cur_speed = aic_calc_speed(width, period, offset, AHD_SYNCRATE_MIN); - wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT, - targ->dv_next_wide_period, - MAX_OFFSET, AHD_SYNCRATE_MIN); - narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT, - targ->dv_next_narrow_period, - MAX_OFFSET, AHD_SYNCRATE_MIN); - fallback_speed = aic_calc_speed(width, period+1, offset, - AHD_SYNCRATE_MIN); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, " - "fallback_speed= %d\n", cur_speed, wide_speed, - narrow_speed, fallback_speed); - } -#endif - - if (cur_speed > 160000) { - /* - * Paced/DT/IU_REQ only transfer speeds. All we - * can do is fallback in terms of syncrate. - */ - period++; - } else if (cur_speed > 80000) { - if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - /* - * Try without IU_REQ as it may be confusing - * an expander. - */ - ppr_options &= ~MSG_EXT_PPR_IU_REQ; - } else { - /* - * Paced/DT only transfer speeds. All we - * can do is fallback in terms of syncrate. - */ - period++; - ppr_options = targ->dv_max_ppr_options; - } - } else if (cur_speed > 3300) { - - /* - * In this range we the following - * options ordered from highest to - * lowest desireability: - * - * o Wide/DT - * o Wide/non-DT - * o Narrow at a potentally higher sync rate. - * - * All modes are tested with and without IU_REQ - * set since using IUs may confuse an expander. - */ - if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - - ppr_options &= ~MSG_EXT_PPR_IU_REQ; - } else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - /* - * Try going non-DT. - */ - ppr_options = targ->dv_max_ppr_options; - ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } else if (targ->dv_last_ppr_options != 0) { - /* - * Try without QAS or any other PPR options. - * We may need a non-PPR message to work with - * an expander. We look at the "last PPR options" - * so we will perform this fallback even if the - * target responded to our PPR negotiation with - * no option bits set. - */ - ppr_options = 0; - } else if (width == MSG_EXT_WDTR_BUS_16_BIT) { - /* - * If the next narrow speed is greater than - * the next wide speed, fallback to narrow. - * Otherwise fallback to the next DT/Wide setting. - * The narrow async speed will always be smaller - * than the wide async speed, so handle this case - * specifically. - */ - ppr_options = targ->dv_max_ppr_options; - if (narrow_speed > fallback_speed - || period >= AHD_ASYNC_XFER_PERIOD) { - targ->dv_next_wide_period = period+1; - width = MSG_EXT_WDTR_BUS_8_BIT; - period = targ->dv_next_narrow_period; - } else { - period++; - } - } else if ((ahd->features & AHD_WIDE) != 0 - && targ->dv_max_width != 0 - && wide_speed >= fallback_speed - && (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD - || period >= AHD_ASYNC_XFER_PERIOD)) { - - /* - * We are narrow. Try falling back - * to the next wide speed with - * all supported ppr options set. - */ - targ->dv_next_narrow_period = period+1; - width = MSG_EXT_WDTR_BUS_16_BIT; - period = targ->dv_next_wide_period; - ppr_options = targ->dv_max_ppr_options; - } else { - /* Only narrow fallback is allowed. */ - period++; - ppr_options = targ->dv_max_ppr_options; - } - } else { - return (-1); - } - offset = MAX_OFFSET; - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_PACED); - ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, FALSE); - if (period == 0) { - period = 0; - offset = 0; - ppr_options = 0; - if (width == MSG_EXT_WDTR_BUS_8_BIT) - targ->dv_next_narrow_period = AHD_ASYNC_XFER_PERIOD; - else - targ->dv_next_wide_period = AHD_ASYNC_XFER_PERIOD; - } - ahd_set_syncrate(ahd, devinfo, period, offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - targ->dv_last_ppr_options = ppr_options; - return (0); -} - -static void -ahd_linux_dv_timeout(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - struct scb *scb; - u_long flags; - - ahd = *((struct ahd_softc **)cmd->device->host->hostdata); - ahd_lock(ahd, &flags); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - printf("%s: Timeout while doing DV command %x.\n", - ahd_name(ahd), cmd->cmnd[0]); - ahd_dump_card_state(ahd); - } -#endif - - /* - * Guard against "done race". No action is - * required if we just completed. - */ - if ((scb = (struct scb *)cmd->host_scribble) == NULL) { - ahd_unlock(ahd, &flags); - return; - } - - /* - * Command has not completed. Mark this - * SCB as having failing status prior to - * resetting the bus, so we get the correct - * error code. - */ - if ((scb->flags & SCB_SENSE) != 0) - ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - else - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE); - - /* - * Add a minimal bus settle delay for devices that are slow to - * respond after bus resets. - */ - ahd_freeze_simq(ahd); - init_timer(&ahd->platform_data->reset_timer); - ahd->platform_data->reset_timer.data = (u_long)ahd; - ahd->platform_data->reset_timer.expires = jiffies + HZ / 2; - ahd->platform_data->reset_timer.function = - (ahd_linux_callback_t *)ahd_release_simq; - add_timer(&ahd->platform_data->reset_timer); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &flags); -} - -static void -ahd_linux_dv_complete(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - - ahd = *((struct ahd_softc **)cmd->device->host->hostdata); - - /* Delete the DV timer before it goes off! */ - scsi_delete_timer(cmd); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s:%c:%d: Command completed, status= 0x%x\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->result); -#endif - - /* Wake up the state machine */ - up(&ahd->platform_data->dv_cmd_sem); -} - -static void -ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ) -{ - uint16_t b; - u_int i; - u_int j; - - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK); - if (targ->dv_buffer1 != NULL) - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK); - - i = 0; - - b = 0x0001; - for (j = 0 ; i < targ->dv_echo_size; j++) { - if (j < 32) { - /* - * 32bytes of sequential numbers. - */ - targ->dv_buffer[i++] = j & 0xff; - } else if (j < 48) { - /* - * 32bytes of repeating 0x0000, 0xffff. - */ - targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00; - } else if (j < 64) { - /* - * 32bytes of repeating 0x5555, 0xaaaa. - */ - targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55; - } else { - /* - * Remaining buffer is filled with a repeating - * patter of: - * - * 0xffff - * ~0x0001 << shifted once in each loop. - */ - if (j & 0x02) { - if (j & 0x01) { - targ->dv_buffer[i++] = ~(b >> 8) & 0xff; - b <<= 1; - if (b == 0x0000) - b = 0x0001; - } else { - targ->dv_buffer[i++] = (~b & 0xff); - } - } else { - targ->dv_buffer[i++] = 0xff; - } - } - } -} - -static u_int -ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - static int warned_user; - u_int tags; - - tags = 0; - if ((ahd->user_discenable & devinfo->target_mask) != 0) { - if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) { - - if (warned_user == 0) { - printf(KERN_WARNING -"aic79xx: WARNING: Insufficient tag_info instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_tag_info array in\n" -"aic79xx: the aic79xx_osm.c source file.\n"); - warned_user++; - } - tags = AHD_MAX_QUEUE; - } else { - adapter_tag_info_t *tag_info; - - tag_info = &aic79xx_tag_info[ahd->unit]; - tags = tag_info->tag_commands[devinfo->target_offset]; - if (tags > AHD_MAX_QUEUE) - tags = AHD_MAX_QUEUE; - } - } - return (tags); -} - -static u_int -ahd_linux_user_dv_setting(struct ahd_softc *ahd) -{ - static int warned_user; - int dv; - - if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) { - - if (warned_user == 0) { - printf(KERN_WARNING -"aic79xx: WARNING: Insufficient dv settings instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_dv_settings array in" -"aic79xx: the aic79xx_osm.c source file.\n"); - warned_user++; - } - dv = -1; - } else { - - dv = aic79xx_dv_settings[ahd->unit]; - } - - if (dv < 0) { /* - * Apply the default. + * Drop down to a single opening, and treat this + * as if the target returned BUSY SCSI status. */ - dv = 1; - if (ahd->seep_config != 0) - dv = (ahd->seep_config->bios_control & CFENABLEDV); - } - return (dv); -} - -static void -ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd) -{ - static int warned_user; - u_int rd_strm_mask; - u_int target_id; - - /* - * If we have specific read streaming info for this controller, - * apply it. Otherwise use the defaults. - */ - if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) { - - if (warned_user == 0) { - - printf(KERN_WARNING -"aic79xx: WARNING: Insufficient rd_strm instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_rd_strm_info array\n" -"aic79xx: in the aic79xx_osm.c source file.\n"); - warned_user++; - } - rd_strm_mask = AIC79XX_CONFIGED_RD_STRM; - } else { - - rd_strm_mask = aic79xx_rd_strm_info[ahd->unit]; - } - for (target_id = 0; target_id < 16; target_id++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - target_id, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, - CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); - tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM; - if ((rd_strm_mask & devinfo.target_mask) != 0) - tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM; - } -} - -/* - * Determines the queue depth for a given device. - */ -static void -ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev) -{ - struct ahd_devinfo devinfo; - u_int tags; - - ahd_compile_devinfo(&devinfo, - ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - tags = ahd_linux_user_tagdepth(ahd, &devinfo); - if (tags != 0 - && dev->scsi_device != NULL - && dev->scsi_device->tagged_supported != 0) { - - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); - ahd_print_devinfo(ahd, &devinfo); - printf("Tagged Queuing enabled. Depth %d\n", tags); - } else { - ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE); - } -} - -static int -ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, - struct scsi_cmnd *cmd) -{ - struct scb *scb; - struct hardware_scb *hscb; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int col_idx; - uint16_t mask; - - /* - * Get an scb to use. - */ - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 - || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - col_idx = AHD_NEVER_COL_IDX; - } else { - col_idx = AHD_BUILD_COL_IDX(cmd->device->id, - cmd->device->lun); - } - if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { - ahd->flags |= AHD_RESOURCE_SHORTAGE; - return SCSI_MLQUEUE_HOST_BUSY; - } - - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; - - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - scb->hscb->task_management = 0; - mask = SCB_GET_TARGET_MASK(ahd, scb); - - if ((ahd->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if (AHD_DV_CMD(cmd) != 0) - scb->flags |= SCB_SILENT; - - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) - scb->flags |= SCB_PACKETIZED; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } - - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else - if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH - && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; - dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); - - scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - if (cmd->use_sg != 0) { - void *sg; - struct scatterlist *cur_seg; - u_int nseg; - int dir; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - dir = cmd->sc_data_direction; - nseg = pci_map_sg(ahd->dev_softc, cur_seg, - cmd->use_sg, dir); - scb->platform_data->xfer_len = 0; - for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { - dma_addr_t addr; - bus_size_t len; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - scb->platform_data->xfer_len += len; - sg = ahd_sg_setup(ahd, scb, sg, addr, len, - /*last*/nseg == 1); - } - } else if (cmd->request_bufflen != 0) { - void *sg; - dma_addr_t addr; - int dir; - - sg = scb->sg_list; - dir = cmd->sc_data_direction; - addr = pci_map_single(ahd->dev_softc, - cmd->request_buffer, - cmd->request_bufflen, dir); - scb->platform_data->xfer_len = cmd->request_bufflen; - scb->platform_data->buf_busaddr = addr; - sg = ahd_sg_setup(ahd, scb, sg, addr, - cmd->request_bufflen, /*last*/TRUE); - } - - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - - /* Update the error counting bucket and dump if needed */ - if (dev->target->cmds_since_error) { - dev->target->cmds_since_error++; - if (dev->target->cmds_since_error > - AHD_LINUX_ERR_THRESH) - dev->target->cmds_since_error = 0; - } - - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - scb->flags |= SCB_ACTIVE; - ahd_queue_scb(ahd, scb); - - return 0; -} - -/* - * SCSI controller interrupt handler. - */ -irqreturn_t -ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) -{ - struct ahd_softc *ahd; - u_long flags; - int ours; - - ahd = (struct ahd_softc *) dev_id; - ahd_lock(ahd, &flags); - ours = ahd_intr(ahd); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &flags); - return IRQ_RETVAL(ours); -} - -void -ahd_platform_flushwork(struct ahd_softc *ahd) -{ - - while (ahd_linux_run_complete_queue(ahd) != NULL) - ; -} - -static struct ahd_linux_target* -ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target) -{ - struct ahd_linux_target *targ; - - targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT); - if (targ == NULL) - return (NULL); - memset(targ, 0, sizeof(*targ)); - targ->channel = channel; - targ->target = target; - targ->ahd = ahd; - targ->flags = AHD_DV_REQUIRED; - ahd->platform_data->targets[target] = targ; - return (targ); -} - -static void -ahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ) -{ - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int our_id; - u_int target_offset; - char channel; - - /* - * Force a negotiation to async/narrow on any - * future command to this device unless a bus - * reset occurs between now and that command. - */ - channel = 'A' + targ->channel; - our_id = ahd->our_id; - target_offset = targ->target; - tinfo = ahd_fetch_transinfo(ahd, channel, our_id, - targ->target, &tstate); - ahd_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD, - channel, ROLE_INITIATOR); - ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS); - ahd->platform_data->targets[target_offset] = NULL; - if (targ->inq_data != NULL) - free(targ->inq_data, M_DEVBUF); - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - if (targ->dv_buffer1 != NULL) - free(targ->dv_buffer1, M_DEVBUF); - free(targ, M_DEVBUF); + dev->openings = 1; + ahd_platform_set_tags(ahd, &devinfo, + (dev->flags & AHD_DEV_Q_BASIC) + ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); + ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); + } } -static struct ahd_linux_device* -ahd_linux_alloc_device(struct ahd_softc *ahd, - struct ahd_linux_target *targ, u_int lun) +static void +ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) { - struct ahd_linux_device *dev; - - dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); - if (dev == NULL) - return (NULL); - memset(dev, 0, sizeof(*dev)); - init_timer(&dev->timer); - dev->flags = AHD_DEV_UNCONFIGURED; - dev->lun = lun; - dev->target = targ; - /* - * We start out life using untagged - * transactions of which we allow one. + * Map CAM error codes into Linux Error codes. We + * avoid the conversion so that the DV code has the + * full error information available when making + * state change decisions. */ - dev->openings = 1; + { + uint32_t status; + u_int new_status; - /* - * Set maxtags to 0. This will be changed if we - * later determine that we are dealing with - * a tagged queuing capable device. - */ - dev->maxtags = 0; - - targ->refcount++; - targ->devices[lun] = dev; - return (dev); + status = ahd_cmd_get_transaction_status(cmd); + switch (status) { + case CAM_REQ_INPROG: + case CAM_REQ_CMP: + case CAM_SCSI_STATUS_ERROR: + new_status = DID_OK; + break; + case CAM_REQ_ABORTED: + new_status = DID_ABORT; + break; + case CAM_BUSY: + new_status = DID_BUS_BUSY; + break; + case CAM_REQ_INVALID: + case CAM_PATH_INVALID: + new_status = DID_BAD_TARGET; + break; + case CAM_SEL_TIMEOUT: + new_status = DID_NO_CONNECT; + break; + case CAM_SCSI_BUS_RESET: + case CAM_BDR_SENT: + new_status = DID_RESET; + break; + case CAM_UNCOR_PARITY: + new_status = DID_PARITY; + break; + case CAM_CMD_TIMEOUT: + new_status = DID_TIME_OUT; + break; + case CAM_UA_ABORT: + case CAM_REQ_CMP_ERR: + case CAM_AUTOSENSE_FAIL: + case CAM_NO_HBA: + case CAM_DATA_RUN_ERR: + case CAM_UNEXP_BUSFREE: + case CAM_SEQUENCE_FAIL: + case CAM_CCB_LEN_ERR: + case CAM_PROVIDE_FAIL: + case CAM_REQ_TERMIO: + case CAM_UNREC_HBA_ERROR: + case CAM_REQ_TOO_BIG: + new_status = DID_ERROR; + break; + case CAM_REQUEUE_REQ: + new_status = DID_REQUEUE; + break; + default: + /* We should never get here */ + new_status = DID_ERROR; + break; + } + + ahd_cmd_set_transaction_status(cmd, new_status); + } + + cmd->scsi_done(cmd); } static void -ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev) +ahd_linux_sem_timeout(u_long arg) { - struct ahd_linux_target *targ; + struct ahd_softc *ahd; + u_long s; - del_timer(&dev->timer); - targ = dev->target; - targ->devices[dev->lun] = NULL; - free(dev, M_DEVBUF); - targ->refcount--; - if (targ->refcount == 0 - && (targ->flags & AHD_DV_REQUIRED) == 0) - ahd_linux_free_target(ahd, targ); + ahd = (struct ahd_softc *)arg; + + ahd_lock(ahd, &s); + if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + up(&ahd->platform_data->eh_sem); + } + ahd_unlock(ahd, &s); } void -ahd_send_async(struct ahd_softc *ahd, char channel, - u_int target, u_int lun, ac_code code, void *arg) +ahd_freeze_simq(struct ahd_softc *ahd) { - switch (code) { - case AC_TRANSFER_NEG: - { - char buf[80]; - struct ahd_linux_target *targ; - struct info_str info; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - info.buffer = buf; - info.length = sizeof(buf); - info.offset = 0; - info.pos = 0; - tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, - target, &tstate); - - /* - * Don't bother reporting results while - * negotiations are still pending. - */ - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options) - if (bootverbose == 0) - break; - - /* - * Don't bother reporting results that - * are identical to those last reported. - */ - targ = ahd->platform_data->targets[target]; - if (targ == NULL) - break; - if (tinfo->curr.period == targ->last_tinfo.period - && tinfo->curr.width == targ->last_tinfo.width - && tinfo->curr.offset == targ->last_tinfo.offset - && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) - if (bootverbose == 0) - break; - - targ->last_tinfo.period = tinfo->curr.period; - targ->last_tinfo.width = tinfo->curr.width; - targ->last_tinfo.offset = tinfo->curr.offset; - targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; - - printf("(%s:%c:", ahd_name(ahd), channel); - if (target == CAM_TARGET_WILDCARD) - printf("*): "); - else - printf("%d): ", target); - ahd_format_transinfo(&info, &tinfo->curr); - if (info.pos < info.length) - *info.buffer = '\0'; - else - buf[info.length - 1] = '\0'; - printf("%s", buf); - break; - } - case AC_SENT_BDR: - { - WARN_ON(lun != CAM_LUN_WILDCARD); - scsi_report_device_reset(ahd->platform_data->host, - channel - 'A', target); - break; + ahd->platform_data->qfrozen++; + if (ahd->platform_data->qfrozen == 1) { + scsi_block_requests(ahd->platform_data->host); + ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, + CAM_LUN_WILDCARD, SCB_LIST_NULL, + ROLE_INITIATOR, CAM_REQUEUE_REQ); } - case AC_BUS_RESET: - if (ahd->platform_data->host != NULL) { - scsi_report_bus_reset(ahd->platform_data->host, - channel - 'A'); - } - break; - default: - panic("ahd_send_async: Unexpected async event"); - } } -/* - * Calls the higher level scsi done function and frees the scb. - */ void -ahd_done(struct ahd_softc *ahd, struct scb *scb) +ahd_release_simq(struct ahd_softc *ahd) { - Scsi_Cmnd *cmd; - struct ahd_linux_device *dev; + u_long s; + int unblock_reqs; - if ((scb->flags & SCB_ACTIVE) == 0) { - printf("SCB %d done'd twice\n", SCB_GET_TAG(scb)); - ahd_dump_card_state(ahd); - panic("Stopping for safety"); - } - LIST_REMOVE(scb, pending_links); - cmd = scb->io_ctx; - dev = scb->platform_data->dev; - dev->active--; - dev->openings++; - if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { - cmd->result &= ~(CAM_DEV_QFRZN << 16); - dev->qfrozen--; + unblock_reqs = 0; + ahd_lock(ahd, &s); + if (ahd->platform_data->qfrozen > 0) + ahd->platform_data->qfrozen--; + if (ahd->platform_data->qfrozen == 0) { + unblock_reqs = 1; } - ahd_linux_unmap_scb(ahd, scb); - + ahd_unlock(ahd, &s); /* - * Guard against stale sense data. - * The Linux mid-layer assumes that sense - * was retrieved anytime the first byte of - * the sense buffer looks "sane". + * There is still a race here. The mid-layer + * should keep its own freeze count and use + * a bottom half handler to run the queues + * so we can unblock with our own lock held. */ - cmd->sense_buffer[0] = 0; - if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) { - uint32_t amount_xferred; + if (unblock_reqs) + scsi_unblock_requests(ahd->platform_data->host); +} - amount_xferred = - ahd_get_transfer_length(scb) - ahd_get_residual(scb); - if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) { - ahd_print_path(ahd, scb); - printf("Set CAM_UNCOR_PARITY\n"); - } -#endif - ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); -#ifdef AHD_REPORT_UNDERFLOWS - /* - * This code is disabled by default as some - * clients of the SCSI system do not properly - * initialize the underflow parameter. This - * results in spurious termination of commands - * that complete as expected (e.g. underflow is - * allowed as command can return variable amounts - * of data. - */ - } else if (amount_xferred < scb->io_ctx->underflow) { - u_int i; +static int +ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) +{ + struct ahd_softc *ahd; + struct ahd_linux_device *dev; + struct scb *pending_scb; + u_int saved_scbptr; + u_int active_scbptr; + u_int last_phase; + u_int saved_scsiid; + u_int cdb_byte; + int retval; + int was_paused; + int paused; + int wait; + int disconnected; + ahd_mode_state saved_modes; + + pending_scb = NULL; + paused = FALSE; + wait = FALSE; + ahd = *(struct ahd_softc **)cmd->device->host->hostdata; + + printf("%s:%d:%d:%d: Attempting to queue a%s message:", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun, + flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + + printf("CDB:"); + for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) + printf(" 0x%x", cmd->cmnd[cdb_byte]); + printf("\n"); + + spin_lock_irq(&ahd->platform_data->spin_lock); - ahd_print_path(ahd, scb); - printf("CDB:"); - for (i = 0; i < scb->io_ctx->cmd_len; i++) - printf(" 0x%x", scb->io_ctx->cmnd[i]); - printf("\n"); - ahd_print_path(ahd, scb); - printf("Saw underflow (%ld of %ld bytes). " - "Treated as error\n", - ahd_get_residual(scb), - ahd_get_transfer_length(scb)); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); -#endif - } else { - ahd_set_transaction_status(scb, CAM_REQ_CMP); - } - } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { - ahd_linux_handle_scsi_status(ahd, dev, scb); - } else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { - dev->flags |= AHD_DEV_UNCONFIGURED; - if (AHD_DV_CMD(cmd) == FALSE) - dev->target->flags &= ~AHD_DV_REQUIRED; - } /* - * Start DV for devices that require it assuming the first command - * sent does not result in a selection timeout. + * First determine if we currently own this command. + * Start by searching the device queue. If not found + * there, check the pending_scb list. If not found + * at all, and the system wanted us to just abort the + * command, return success. */ - if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT - && (dev->target->flags & AHD_DV_REQUIRED) != 0) - ahd_linux_start_dv(ahd); + dev = scsi_transport_device_data(cmd->device); + + if (dev == NULL) { + /* + * No target device for this command exists, + * so we must not still own the command. + */ + printf("%s:%d:%d:%d: Is not an active device\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + retval = SUCCESS; + goto no_cmd; + } - if (dev->openings == 1 - && ahd_get_transaction_status(scb) == CAM_REQ_CMP - && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) - dev->tag_success_count++; /* - * Some devices deal with temporary internal resource - * shortages by returning queue full. When the queue - * full occurrs, we throttle back. Slowly try to get - * back to our previous queue depth. + * See if we can find a matching cmd in the pending list. */ - if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) { - dev->tag_success_count = 0; - dev->openings++; + LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { + if (pending_scb->io_ctx == cmd) + break; } - if (dev->active == 0) - dev->commands_since_idle_or_otag = 0; - - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); + if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printf("Recovery SCB completes\n"); - if (ahd_get_transaction_status(scb) == CAM_BDR_SENT - || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; - up(&ahd->platform_data->eh_sem); + /* Any SCB for this device will do for a target reset */ + LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { + if (ahd_match_scb(ahd, pending_scb, cmd->device->id, + cmd->device->channel + 'A', + CAM_LUN_WILDCARD, + SCB_LIST_NULL, ROLE_INITIATOR) == 0) + break; } } - ahd_free_scb(ahd, scb); - ahd_linux_queue_cmd_complete(ahd, cmd); - - if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0 - && LIST_FIRST(&ahd->pending_scbs) == NULL) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY; - up(&ahd->platform_data->dv_sem); + if (pending_scb == NULL) { + printf("%s:%d:%d:%d: Command not found\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + goto no_cmd; } -} -static void -ahd_linux_handle_scsi_status(struct ahd_softc *ahd, - struct ahd_linux_device *dev, struct scb *scb) -{ - struct ahd_devinfo devinfo; + if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { + /* + * We can't queue two recovery actions using the same SCB + */ + retval = FAILED; + goto done; + } - ahd_compile_devinfo(&devinfo, - ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - /* - * We don't currently trust the mid-layer to - * properly deal with queue full or busy. So, - * when one occurs, we tell the mid-layer to - * unconditionally requeue the command to us - * so that we can retry it ourselves. We also - * implement our own throttling mechanism so - * we don't clobber the device with too many - * commands. + * Ensure that the card doesn't do anything + * behind our back. Also make sure that we + * didn't "just" miss an interrupt that would + * affect this cmd. */ - switch (ahd_get_scsi_status(scb)) { - default: - break; - case SCSI_STATUS_CHECK_COND: - case SCSI_STATUS_CMD_TERMINATED: - { - Scsi_Cmnd *cmd; + was_paused = ahd_is_paused(ahd); + ahd_pause_and_flushwork(ahd); + paused = TRUE; - /* - * Copy sense information to the OS's cmd - * structure if it is available. - */ - cmd = scb->io_ctx; - if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) { - struct scsi_status_iu_header *siu; - u_int sense_size; - u_int sense_offset; + if ((pending_scb->flags & SCB_ACTIVE) == 0) { + printf("%s:%d:%d:%d: Command already completed\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + goto no_cmd; + } - if (scb->flags & SCB_SENSE) { - sense_size = MIN(sizeof(struct scsi_sense_data) - - ahd_get_sense_residual(scb), - sizeof(cmd->sense_buffer)); - sense_offset = 0; - } else { - /* - * Copy only the sense data into the provided - * buffer. - */ - siu = (struct scsi_status_iu_header *) - scb->sense_data; - sense_size = MIN(scsi_4btoul(siu->sense_length), - sizeof(cmd->sense_buffer)); - sense_offset = SIU_SENSE_OFFSET(siu); - } + printf("%s: At time of recovery, card was %spaused\n", + ahd_name(ahd), was_paused ? "" : "not "); + ahd_dump_card_state(ahd); - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - memcpy(cmd->sense_buffer, - ahd_get_sense_buf(ahd, scb) - + sense_offset, sense_size); - cmd->result |= (DRIVER_SENSE << 24); + disconnected = TRUE; + if (flag == SCB_ABORT) { + if (ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', + cmd->device->lun, + pending_scb->hscb->tag, + ROLE_INITIATOR, CAM_REQ_ABORTED, + SEARCH_COMPLETE) > 0) { + printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + retval = SUCCESS; + goto done; + } + } else if (ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', + cmd->device->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_COUNT) > 0) { + disconnected = FALSE; + } -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_SENSE) { - int i; + saved_modes = ahd_save_modes(ahd); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + last_phase = ahd_inb(ahd, LASTPHASE); + saved_scbptr = ahd_get_scbptr(ahd); + active_scbptr = saved_scbptr; + if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { + struct scb *bus_scb; - printf("Copied %d bytes of sense data at %d:", - sense_size, sense_offset); - for (i = 0; i < sense_size; i++) { - if ((i & 0xF) == 0) - printf("\n"); - printf("0x%x ", cmd->sense_buffer[i]); - } - printf("\n"); - } -#endif - } - break; + bus_scb = ahd_lookup_scb(ahd, active_scbptr); + if (bus_scb == pending_scb) + disconnected = FALSE; + else if (flag != SCB_ABORT + && ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid + && ahd_inb(ahd, SAVED_LUN) == SCB_GET_LUN(pending_scb)) + disconnected = FALSE; } - case SCSI_STATUS_QUEUE_FULL: - { + + /* + * At this point, pending_scb is the scb associated with the + * passed in command. That command is currently active on the + * bus or is in the disconnected state. + */ + saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); + if (last_phase != P_BUSFREE + && (SCB_GET_TAG(pending_scb) == active_scbptr + || (flag == SCB_DEVICE_RESET + && SCSIID_TARGET(ahd, saved_scsiid) == cmd->device->id))) { + /* - * By the time the core driver has returned this - * command, all other commands that were queued - * to us but not the device have been returned. - * This ensures that dev->active is equal to - * the number of commands actually queued to - * the device. + * We're active on the bus, so assert ATN + * and hope that the target responds. */ - dev->tag_success_count = 0; - if (dev->active != 0) { + pending_scb = ahd_lookup_scb(ahd, active_scbptr); + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + ahd_outb(ahd, MSG_OUT, HOST_MSG); + ahd_outb(ahd, SCSISIGO, last_phase|ATNO); + printf("%s:%d:%d:%d: Device is active, asserting ATN\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + wait = TRUE; + } else if (disconnected) { + + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + */ + pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; + ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); + pending_scb->hscb->cdb_len = 0; + pending_scb->hscb->task_attribute = 0; + pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; + + if ((pending_scb->flags & SCB_PACKETIZED) != 0) { /* - * Drop our opening count to the number - * of commands currently outstanding. + * Mark the SCB has having an outstanding + * task management function. Should the command + * complete normally before the task management + * function can be sent, the host will be notified + * to abort our requeued SCB. */ - dev->openings = 0; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_QFULL) != 0) { - ahd_print_path(ahd, scb); - printf("Dropping tag count to %d\n", - dev->active); - } -#endif - if (dev->active == dev->tags_on_last_queuefull) { - - dev->last_queuefull_same_count++; - /* - * If we repeatedly see a queue full - * at the same queue depth, this - * device has a fixed number of tag - * slots. Lock in this tag depth - * so we stop seeing queue fulls from - * this device. - */ - if (dev->last_queuefull_same_count - == AHD_LOCK_TAGS_COUNT) { - dev->maxtags = dev->active; - ahd_print_path(ahd, scb); - printf("Locking max tag count at %d\n", - dev->active); - } - } else { - dev->tags_on_last_queuefull = dev->active; - dev->last_queuefull_same_count = 0; - } - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_platform_set_tags(ahd, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) - ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); - break; + ahd_outb(ahd, SCB_TASK_MANAGEMENT, + pending_scb->hscb->task_management); + } else { + /* + * If non-packetized, set the MK_MESSAGE control + * bit indicating that we desire to send a message. + * We also set the disconnected flag since there is + * no guarantee that our SCB control byte matches + * the version on the card. We don't want the + * sequencer to abort the command thinking an + * unsolicited reselection occurred. + */ + pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + + /* + * The sequencer will never re-reference the + * in-core SCB. To make sure we are notified + * during reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + ahd_outb(ahd, SCB_CONTROL, + ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); } + /* - * Drop down to a single opening, and treat this - * as if the target returned BUSY SCSI status. - */ - dev->openings = 1; - ahd_platform_set_tags(ahd, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) - ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); - ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); - /* FALLTHROUGH */ - } - case SCSI_STATUS_BUSY: - /* - * Set a short timer to defer sending commands for - * a bit since Linux will not delay in this case. + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. */ - if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) { - printf("%s:%c:%d: Device Timer still active during " - "busy processing\n", ahd_name(ahd), - dev->target->channel, dev->target->target); - break; - } - dev->flags |= AHD_DEV_TIMER_ACTIVE; - dev->qfrozen++; - init_timer(&dev->timer); - dev->timer.data = (u_long)dev; - dev->timer.expires = jiffies + (HZ/2); - dev->timer.function = ahd_linux_dev_timed_unfreeze; - add_timer(&dev->timer); - break; + ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', cmd->device->lun, + SCB_LIST_NULL, ROLE_INITIATOR, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + ahd_qinfifo_requeue_tail(ahd, pending_scb); + ahd_set_scbptr(ahd, saved_scbptr); + ahd_print_path(ahd, pending_scb); + printf("Device is disconnected, re-queuing SCB\n"); + wait = TRUE; + } else { + printf("%s:%d:%d:%d: Unable to deliver message\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + retval = FAILED; + goto done; } -} - -static void -ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd) -{ - /* - * Typically, the complete queue has very few entries - * queued to it before the queue is emptied by - * ahd_linux_run_complete_queue, so sorting the entries - * by generation number should be inexpensive. - * We perform the sort so that commands that complete - * with an error are retuned in the order origionally - * queued to the controller so that any subsequent retries - * are performed in order. The underlying ahd routines do - * not guarantee the order that aborted commands will be - * returned to us. - */ - struct ahd_completeq *completeq; - struct ahd_cmd *list_cmd; - struct ahd_cmd *acmd; +no_cmd: /* - * Map CAM error codes into Linux Error codes. We - * avoid the conversion so that the DV code has the - * full error information available when making - * state change decisions. + * Our assumption is that if we don't have the command, no + * recovery action was required, so we return success. Again, + * the semantics of the mid-layer recovery engine are not + * well defined, so this may change in time. */ - if (AHD_DV_CMD(cmd) == FALSE) { - uint32_t status; - u_int new_status; + retval = SUCCESS; +done: + if (paused) + ahd_unpause(ahd); + if (wait) { + struct timer_list timer; + int ret; - status = ahd_cmd_get_transaction_status(cmd); - if (status != CAM_REQ_CMP) { - struct ahd_linux_device *dev; - struct ahd_devinfo devinfo; - cam_status cam_status; - uint32_t action; - u_int scsi_status; - - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, - cmd->device->lun, - /*alloc*/FALSE); - - if (dev == NULL) - goto no_fallback; - - ahd_compile_devinfo(&devinfo, - ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A':'B', - ROLE_INITIATOR); - - scsi_status = ahd_cmd_get_scsi_status(cmd); - cam_status = ahd_cmd_get_transaction_status(cmd); - action = aic_error_action(cmd, dev->target->inq_data, - cam_status, scsi_status); - if ((action & SSQ_FALLBACK) != 0) { - - /* Update stats */ - dev->target->errors_detected++; - if (dev->target->cmds_since_error == 0) - dev->target->cmds_since_error++; - else { - dev->target->cmds_since_error = 0; - ahd_linux_fallback(ahd, &devinfo); - } - } - } -no_fallback: - switch (status) { - case CAM_REQ_INPROG: - case CAM_REQ_CMP: - case CAM_SCSI_STATUS_ERROR: - new_status = DID_OK; - break; - case CAM_REQ_ABORTED: - new_status = DID_ABORT; - break; - case CAM_BUSY: - new_status = DID_BUS_BUSY; - break; - case CAM_REQ_INVALID: - case CAM_PATH_INVALID: - new_status = DID_BAD_TARGET; - break; - case CAM_SEL_TIMEOUT: - new_status = DID_NO_CONNECT; - break; - case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: - new_status = DID_RESET; - break; - case CAM_UNCOR_PARITY: - new_status = DID_PARITY; - break; - case CAM_CMD_TIMEOUT: - new_status = DID_TIME_OUT; - break; - case CAM_UA_ABORT: - case CAM_REQ_CMP_ERR: - case CAM_AUTOSENSE_FAIL: - case CAM_NO_HBA: - case CAM_DATA_RUN_ERR: - case CAM_UNEXP_BUSFREE: - case CAM_SEQUENCE_FAIL: - case CAM_CCB_LEN_ERR: - case CAM_PROVIDE_FAIL: - case CAM_REQ_TERMIO: - case CAM_UNREC_HBA_ERROR: - case CAM_REQ_TOO_BIG: - new_status = DID_ERROR; - break; - case CAM_REQUEUE_REQ: - /* - * If we want the request requeued, make sure there - * are sufficent retries. In the old scsi error code, - * we used to be able to specify a result code that - * bypassed the retry count. Now we must use this - * hack. We also "fake" a check condition with - * a sense code of ABORTED COMMAND. This seems to - * evoke a retry even if this command is being sent - * via the eh thread. Ick! Ick! Ick! - */ - if (cmd->retries > 0) - cmd->retries--; - new_status = DID_OK; - ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); - cmd->result |= (DRIVER_SENSE << 24); - memset(cmd->sense_buffer, 0, - sizeof(cmd->sense_buffer)); - cmd->sense_buffer[0] = SSD_ERRCODE_VALID - | SSD_CURRENT_ERROR; - cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND; - break; - default: - /* We should never get here */ - new_status = DID_ERROR; - break; + ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; + spin_unlock_irq(&ahd->platform_data->spin_lock); + init_timer(&timer); + timer.data = (u_long)ahd; + timer.expires = jiffies + (5 * HZ); + timer.function = ahd_linux_sem_timeout; + add_timer(&timer); + printf("Recovery code sleeping\n"); + down(&ahd->platform_data->eh_sem); + printf("Recovery code awake\n"); + ret = del_timer_sync(&timer); + if (ret == 0) { + printf("Timer Expired\n"); + retval = FAILED; } - - ahd_cmd_set_transaction_status(cmd, new_status); + spin_lock_irq(&ahd->platform_data->spin_lock); } - - completeq = &ahd->platform_data->completeq; - list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahd_cmd *)cmd; - while (list_cmd != NULL - && acmd_scsi_cmd(list_cmd).serial_number - < acmd_scsi_cmd(acmd).serial_number) - list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); - if (list_cmd != NULL) - TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); - else - TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); + spin_unlock_irq(&ahd->platform_data->spin_lock); + return (retval); } -static void -ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) +static void ahd_linux_exit(void); + +static void ahd_linux_set_width(struct scsi_target *starget, int width) { - struct scsi_inquiry_data *sid; - struct ahd_initiator_tinfo *tinfo; - struct ahd_transinfo *user; - struct ahd_transinfo *goal; - struct ahd_transinfo *curr; - struct ahd_tmode_tstate *tstate; - struct ahd_linux_device *dev; - u_int width; - u_int period; - u_int offset; - u_int ppr_options; - u_int trans_version; - u_int prot_version; + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_devinfo devinfo; + unsigned long flags; - /* - * Determine if this lun actually exists. If so, - * hold on to its corresponding device structure. - * If not, make sure we release the device and - * don't bother processing the rest of this inquiry - * command. - */ - dev = ahd_linux_get_device(ahd, devinfo->channel - 'A', - devinfo->target, devinfo->lun, - /*alloc*/TRUE); + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_lock(ahd, &flags); + ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_period(struct scsi_target *starget, int period) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options; + unsigned long flags; + unsigned long offset = tinfo->goal.offset; - sid = (struct scsi_inquiry_data *)dev->target->inq_data; - if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { + if (offset == 0) + offset = MAX_OFFSET; - dev->flags &= ~AHD_DEV_UNCONFIGURED; - } else { - dev->flags |= AHD_DEV_UNCONFIGURED; - return; + if (period < 8) + period = 8; + if (period < 10) { + ppr_options |= MSG_EXT_PPR_DT_REQ; + if (period == 8) + ppr_options |= MSG_EXT_PPR_IU_REQ; } - /* - * Update our notion of this device's transfer - * negotiation capabilities. - */ - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - user = &tinfo->user; - goal = &tinfo->goal; - curr = &tinfo->curr; - width = user->width; - period = user->period; - offset = user->offset; - ppr_options = user->ppr_options; - trans_version = user->transport_version; - prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid)); + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); - /* - * Only attempt SPI3/4 once we've verified that - * the device claims to support SPI3/4 features. - */ - if (prot_version < SCSI_REV_2) - trans_version = SID_ANSI_REV(sid); - else - trans_version = SCSI_REV_2; - - if ((sid->flags & SID_WBus16) == 0) - width = MSG_EXT_WDTR_BUS_8_BIT; - if ((sid->flags & SID_Sync) == 0) { - period = 0; - offset = 0; - ppr_options = 0; + /* all PPR requests apart from QAS require wide transfers */ + if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) { + if (spi_width(starget) == 0) + ppr_options &= MSG_EXT_PPR_QAS_REQ; } - if ((sid->spi3data & SID_SPI_QAS) == 0) - ppr_options &= ~MSG_EXT_PPR_QAS_REQ; - if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) - ppr_options &= MSG_EXT_PPR_QAS_REQ; - if ((sid->spi3data & SID_SPI_IUS) == 0) - ppr_options &= (MSG_EXT_PPR_DT_REQ - | MSG_EXT_PPR_QAS_REQ); - - if (prot_version > SCSI_REV_2 - && ppr_options != 0) - trans_version = user->transport_version; - - ahd_validate_width(ahd, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN); + ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); - ahd_validate_offset(ahd, /*tinfo limit*/NULL, period, - &offset, width, ROLE_UNKNOWN); - if (offset == 0 || period == 0) { - period = 0; - offset = 0; - ppr_options = 0; - } - /* Apply our filtered user settings. */ - curr->transport_version = trans_version; - curr->protocol_version = prot_version; - ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_syncrate(ahd, devinfo, period, offset, ppr_options, - AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); } -void -ahd_freeze_simq(struct ahd_softc *ahd) +static void ahd_linux_set_offset(struct scsi_target *starget, int offset) { - ahd->platform_data->qfrozen++; - if (ahd->platform_data->qfrozen == 1) { - scsi_block_requests(ahd->platform_data->host); - ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = 0; + unsigned int period = 0; + unsigned long flags; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + if (offset != 0) { + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); } + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, + AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); } -void -ahd_release_simq(struct ahd_softc *ahd) +static void ahd_linux_set_dt(struct scsi_target *starget, int dt) { - u_long s; - int unblock_reqs; - - unblock_reqs = 0; - ahd_lock(ahd, &s); - if (ahd->platform_data->qfrozen > 0) - ahd->platform_data->qfrozen--; - if (ahd->platform_data->qfrozen == 0) { - unblock_reqs = 1; - } - if (AHD_DV_SIMQ_FROZEN(ahd) - && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE; - up(&ahd->platform_data->dv_sem); - } - ahd_unlock(ahd, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) - scsi_unblock_requests(ahd->platform_data->host); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_DT_REQ; + unsigned int period = tinfo->goal.period; + unsigned long flags; + + if (dt) { + ppr_options |= MSG_EXT_PPR_DT_REQ; + if (period > 9) + period = 9; /* at least 12.5ns for DT */ + } else if (period <= 9) + period = 10; /* If resetting DT, period must be >= 25ns */ + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); } -static void -ahd_linux_sem_timeout(u_long arg) +static void ahd_linux_set_qas(struct scsi_target *starget, int qas) { - struct scb *scb; - struct ahd_softc *ahd; - u_long s; - - scb = (struct scb *)arg; - ahd = scb->ahd_softc; - ahd_lock(ahd, &s); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; - up(&ahd->platform_data->eh_sem); - } - ahd_unlock(ahd, &s); + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_QAS_REQ; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (qas) + ppr_options |= MSG_EXT_PPR_QAS_REQ; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); } -static void -ahd_linux_dev_timed_unfreeze(u_long arg) +static void ahd_linux_set_iu(struct scsi_target *starget, int iu) { - struct ahd_linux_device *dev; - struct ahd_softc *ahd; - u_long s; + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_IU_REQ; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (iu) + ppr_options |= MSG_EXT_PPR_IU_REQ; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} - dev = (struct ahd_linux_device *)arg; - ahd = dev->target->ahd; - ahd_lock(ahd, &s); - dev->flags &= ~AHD_DEV_TIMER_ACTIVE; - if (dev->qfrozen > 0) - dev->qfrozen--; - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0) - ahd_linux_free_device(ahd, dev); - ahd_unlock(ahd, &s); +static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_RD_STRM; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (rdstrm) + ppr_options |= MSG_EXT_PPR_RD_STRM; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); } +static struct spi_function_template ahd_linux_transport_functions = { + .set_offset = ahd_linux_set_offset, + .show_offset = 1, + .set_period = ahd_linux_set_period, + .show_period = 1, + .set_width = ahd_linux_set_width, + .show_width = 1, + .set_dt = ahd_linux_set_dt, + .show_dt = 1, + .set_iu = ahd_linux_set_iu, + .show_iu = 1, + .set_qas = ahd_linux_set_qas, + .show_qas = 1, + .set_rd_strm = ahd_linux_set_rd_strm, + .show_rd_strm = 1, +}; + + + static int __init ahd_linux_init(void) { - return ahd_linux_detect(&aic79xx_driver_template); + ahd_linux_transport_template = spi_attach_transport(&ahd_linux_transport_functions); + 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)); + if (ahd_linux_detect(&aic79xx_driver_template) > 0) + return 0; + spi_release_transport(ahd_linux_transport_template); + ahd_linux_exit(); + return -ENODEV; } static void __exit ahd_linux_exit(void) { - struct ahd_softc *ahd; - - /* - * Shutdown DV threads before going into the SCSI mid-layer. - * This avoids situations where the mid-layer locks the entire - * kernel so that waiting for our DV threads to exit leads - * to deadlock. - */ - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - - ahd_linux_kill_dv_thread(ahd); - } - ahd_linux_pci_exit(); + spi_release_transport(ahd_linux_transport_template); } module_init(ahd_linux_init); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 792e97fef5b..46edcf3e4e6 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -42,6 +42,7 @@ #ifndef _AIC79XX_LINUX_H_ #define _AIC79XX_LINUX_H_ +#include #include #include #include @@ -49,18 +50,23 @@ #include #include #include +#include #include +#include #include #include -#include /* For tasklet support. */ -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include /* Core SCSI definitions */ #define AIC_LIB_PREFIX ahd -#include "scsi.h" -#include /* Name space conflict with BSD queue macros */ #ifdef LIST_HEAD @@ -95,7 +101,7 @@ /************************* Forward Declarations *******************************/ struct ahd_softc; typedef struct pci_dev *ahd_dev_softc_t; -typedef Scsi_Cmnd *ahd_io_ctx_t; +typedef struct scsi_cmnd *ahd_io_ctx_t; /******************************* Byte Order ***********************************/ #define ahd_htobe16(x) cpu_to_be16(x) @@ -115,7 +121,7 @@ typedef Scsi_Cmnd *ahd_io_ctx_t; /************************* Configuration Data *********************************/ extern uint32_t aic79xx_allow_memio; extern int aic79xx_detect_complete; -extern Scsi_Host_Template aic79xx_driver_template; +extern struct scsi_host_template aic79xx_driver_template; /***************************** Bus Space/DMA **********************************/ @@ -145,11 +151,7 @@ struct ahd_linux_dma_tag }; typedef struct ahd_linux_dma_tag* bus_dma_tag_t; -struct ahd_linux_dmamap -{ - dma_addr_t bus_addr; -}; -typedef struct ahd_linux_dmamap* bus_dmamap_t; +typedef dma_addr_t bus_dmamap_t; typedef int bus_dma_filter_t(void*, dma_addr_t); typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); @@ -226,12 +228,12 @@ typedef struct timer_list ahd_timer_t; #define ahd_timer_init init_timer #define ahd_timer_stop del_timer_sync typedef void ahd_linux_callback_t (u_long); -static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec, +static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg); static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec); static __inline void -ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg) +ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg) { struct ahd_softc *ahd; @@ -382,62 +384,12 @@ struct ahd_linux_device { */ u_int commands_since_idle_or_otag; #define AHD_OTAG_THRESH 500 - - int lun; - Scsi_Device *scsi_device; - struct ahd_linux_target *target; }; -typedef enum { - AHD_DV_REQUIRED = 0x01, - AHD_INQ_VALID = 0x02, - AHD_BASIC_DV = 0x04, - AHD_ENHANCED_DV = 0x08 -} ahd_linux_targ_flags; - -/* DV States */ -typedef enum { - AHD_DV_STATE_EXIT = 0, - AHD_DV_STATE_INQ_SHORT_ASYNC, - AHD_DV_STATE_INQ_ASYNC, - AHD_DV_STATE_INQ_ASYNC_VERIFY, - AHD_DV_STATE_TUR, - AHD_DV_STATE_REBD, - AHD_DV_STATE_INQ_VERIFY, - AHD_DV_STATE_WEB, - AHD_DV_STATE_REB, - AHD_DV_STATE_SU, - AHD_DV_STATE_BUSY -} ahd_dv_state; - struct ahd_linux_target { - struct ahd_linux_device *devices[AHD_NUM_LUNS]; - int channel; - int target; - int refcount; + struct scsi_device *sdev[AHD_NUM_LUNS]; struct ahd_transinfo last_tinfo; struct ahd_softc *ahd; - ahd_linux_targ_flags flags; - struct scsi_inquiry_data *inq_data; - /* - * The next "fallback" period to use for narrow/wide transfers. - */ - uint8_t dv_next_narrow_period; - uint8_t dv_next_wide_period; - uint8_t dv_max_width; - uint8_t dv_max_ppr_options; - uint8_t dv_last_ppr_options; - u_int dv_echo_size; - ahd_dv_state dv_state; - u_int dv_state_retry; - uint8_t *dv_buffer; - uint8_t *dv_buffer1; - - /* - * Cumulative counter of errors. - */ - u_long errors_detected; - u_long cmds_since_error; }; /********************* Definitions Required by the Core ***********************/ @@ -452,16 +404,11 @@ struct ahd_linux_target { /* * Per-SCB OSM storage. */ -typedef enum { - AHD_SCB_UP_EH_SEM = 0x1 -} ahd_linux_scb_flags; - struct scb_platform_data { struct ahd_linux_device *dev; dma_addr_t buf_busaddr; uint32_t xfer_len; uint32_t sense_resid; /* Auto-Sense residual */ - ahd_linux_scb_flags flags; }; /* @@ -470,42 +417,24 @@ struct scb_platform_data { * alignment restrictions of the various platforms supported by * this driver. */ -typedef enum { - AHD_DV_WAIT_SIMQ_EMPTY = 0x01, - AHD_DV_WAIT_SIMQ_RELEASE = 0x02, - AHD_DV_ACTIVE = 0x04, - AHD_DV_SHUTDOWN = 0x08, - AHD_RUN_CMPLT_Q_TIMER = 0x10 -} ahd_linux_softc_flags; - -TAILQ_HEAD(ahd_completeq, ahd_cmd); - struct ahd_platform_data { /* * Fields accessed from interrupt context. */ - struct ahd_linux_target *targets[AHD_NUM_TARGETS]; - struct ahd_completeq completeq; + struct scsi_target *starget[AHD_NUM_TARGETS]; spinlock_t spin_lock; u_int qfrozen; - pid_t dv_pid; - struct timer_list completeq_timer; struct timer_list reset_timer; - struct timer_list stats_timer; struct semaphore eh_sem; - struct semaphore dv_sem; - struct semaphore dv_cmd_sem; /* XXX This needs to be in - * the target struct - */ - struct scsi_device *dv_scsi_dev; struct Scsi_Host *host; /* pointer to scsi host */ #define AHD_LINUX_NOIRQ ((uint32_t)~0) uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ uint64_t hw_dma_mask; - ahd_linux_softc_flags flags; +#define AHD_SCB_UP_EH_SEM 0x1 + uint32_t flags; }; /************************** OS Utility Wrappers *******************************/ @@ -622,7 +551,7 @@ ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count) /**************************** Initialization **********************************/ int ahd_linux_register_host(struct ahd_softc *, - Scsi_Host_Template *); + struct scsi_host_template *); uint64_t ahd_linux_get_memsize(void); @@ -643,17 +572,6 @@ static __inline void ahd_lockinit(struct ahd_softc *); static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags); static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags); -/* Lock acquisition and release of the above lock in midlayer entry points. */ -static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *, - unsigned long *flags); -static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *, - unsigned long *flags); - -/* Lock held during command compeletion to the upper layer */ -static __inline void ahd_done_lockinit(struct ahd_softc *); -static __inline void ahd_done_lock(struct ahd_softc *, unsigned long *flags); -static __inline void ahd_done_unlock(struct ahd_softc *, unsigned long *flags); - /* Lock held during ahd_list manipulation and ahd softc frees */ extern spinlock_t ahd_list_spinlock; static __inline void ahd_list_lockinit(void); @@ -678,57 +596,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); } -static __inline void -ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags) -{ - /* - * In 2.5.X and some 2.4.X versions, the midlayer takes our - * lock just before calling us, so we avoid locking again. - * For other kernel versions, the io_request_lock is taken - * just before our entry point is called. In this case, we - * trade the io_request_lock for our per-softc lock. - */ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&io_request_lock); - spin_lock(&ahd->platform_data->spin_lock); -#endif -} - -static __inline void -ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&ahd->platform_data->spin_lock); - spin_lock(&io_request_lock); -#endif -} - -static __inline void -ahd_done_lockinit(struct ahd_softc *ahd) -{ - /* - * In 2.5.X, our own lock is held during completions. - * In previous versions, the io_request_lock is used. - * In either case, we can't initialize this lock again. - */ -} - -static __inline void -ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_lock(&io_request_lock); -#endif -} - -static __inline void -ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&io_request_lock); -#endif -} - static __inline void ahd_list_lockinit(void) { @@ -909,20 +776,14 @@ ahd_flush_device_writes(struct ahd_softc *ahd) int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -/*************************** Domain Validation ********************************/ -#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) -#define AHD_DV_SIMQ_FROZEN(ahd) \ - ((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0) \ - && (ahd)->platform_data->qfrozen == 1) - /*********************** Transaction Access Wrappers **************************/ -static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); +static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); static __inline void ahd_set_transaction_status(struct scb *, uint32_t); -static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); +static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); static __inline void ahd_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); static __inline uint32_t ahd_get_transaction_status(struct scb *); -static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); static __inline uint32_t ahd_get_scsi_status(struct scb *); static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); static __inline u_long ahd_get_transfer_length(struct scb *); @@ -941,7 +802,7 @@ static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, static __inline void ahd_freeze_scb(struct scb *scb); static __inline -void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) +void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; @@ -954,7 +815,7 @@ void ahd_set_transaction_status(struct scb *scb, uint32_t status) } static __inline -void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) +void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~0xFFFF; cmd->result |= status; @@ -967,7 +828,7 @@ void ahd_set_scsi_status(struct scb *scb, uint32_t status) } static __inline -uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd) +uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) { return ((cmd->result >> 16) & CAM_STATUS_MASK); } @@ -979,7 +840,7 @@ uint32_t ahd_get_transaction_status(struct scb *scb) } static __inline -uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd) +uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) { return (cmd->result & 0xFFFF); } diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 9c631a494ed..2058aa9b5c8 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -49,7 +49,7 @@ static void ahd_dump_target_state(struct ahd_softc *ahd, u_int our_id, char channel, u_int target_id, u_int target_offset); static void ahd_dump_device_state(struct info_str *info, - struct ahd_linux_device *dev); + struct scsi_device *sdev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length); @@ -167,6 +167,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, u_int target_offset) { struct ahd_linux_target *targ; + struct scsi_target *starget; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; int lun; @@ -176,7 +177,8 @@ 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); - targ = ahd->platform_data->targets[target_offset]; + starget = ahd->platform_data->starget[target_offset]; + targ = scsi_transport_target_data(starget); if (targ == NULL) return; @@ -184,12 +186,11 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, ahd_format_transinfo(info, &tinfo->goal); copy_info(info, "\tCurr: "); ahd_format_transinfo(info, &tinfo->curr); - copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected); for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_linux_device *dev; + struct scsi_device *dev; - dev = targ->devices[lun]; + dev = targ->sdev[lun]; if (dev == NULL) continue; @@ -199,10 +200,13 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, } static void -ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev) +ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev) { + struct ahd_linux_device *dev = scsi_transport_device_data(sdev); + copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", - dev->target->channel + 'A', dev->target->target, dev->lun); + sdev->sdev_target->channel + 'A', + sdev->sdev_target->id, sdev->lun); copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); -- cgit v1.2.3 From a4b53a11806f5c0824eb4115b1de8206ed7bb89a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 1 Aug 2005 09:52:56 +0200 Subject: [SCSI] aic79xx: DV parameter settings This patch updates various scsi_transport_spi parameters with the actual parameters used by the driver internally. Domain Validation for all devices should now work properly. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 231 ++++++++++++++++++++++++++++++++++--- 1 file changed, 218 insertions(+), 13 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 70997ca28ba..cf8e0ca830a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1636,9 +1636,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_period(starget) = tinfo->curr.period; spi_width(starget) = tinfo->curr.width; spi_offset(starget) = tinfo->curr.offset; - spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ; - spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ; - spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ; + spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; + spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; + spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2318,6 +2318,18 @@ done: static void ahd_linux_exit(void); +static void ahd_linux_set_xferflags(struct scsi_target *starget, unsigned int ppr_options, unsigned int period) +{ + spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; + spi_dt(starget) = (ppr_options & MSG_EXT_PPR_DT_REQ)? 1 : 0; + spi_iu(starget) = (ppr_options & MSG_EXT_PPR_IU_REQ) ? 1 : 0; + spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; + spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; + spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; + spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; + spi_period(starget) = period; +} + static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2343,9 +2355,14 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) shost->this_id, starget->id, &tstate); struct ahd_devinfo devinfo; unsigned int ppr_options = tinfo->goal.ppr_options; + unsigned int dt; unsigned long flags; unsigned long offset = tinfo->goal.offset; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: set period to %d\n", ahd_name(ahd), period); +#endif if (offset == 0) offset = MAX_OFFSET; @@ -2357,6 +2374,8 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ppr_options |= MSG_EXT_PPR_IU_REQ; } + dt = ppr_options & MSG_EXT_PPR_DT_REQ; + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); @@ -2366,7 +2385,11 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ppr_options &= MSG_EXT_PPR_QAS_REQ; } - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2385,15 +2408,24 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset) struct ahd_devinfo devinfo; unsigned int ppr_options = 0; unsigned int period = 0; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: set offset to %d\n", ahd_name(ahd), offset); +#endif + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); if (offset != 0) { period = tinfo->goal.period; ppr_options = tinfo->goal.ppr_options; - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); } + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2415,17 +2447,28 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) unsigned int period = tinfo->goal.period; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s DT\n", ahd_name(ahd), + dt ? "enabling" : "disabling"); +#endif if (dt) { ppr_options |= MSG_EXT_PPR_DT_REQ; if (period > 9) period = 9; /* at least 12.5ns for DT */ - } else if (period <= 9) - period = 10; /* If resetting DT, period must be >= 25ns */ - + } else { + if (period <= 9) + period = 10; /* If resetting DT, period must be >= 25ns */ + /* IU is invalid without DT set */ + ppr_options &= ~MSG_EXT_PPR_IU_REQ; + } ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2445,16 +2488,28 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_QAS_REQ; unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned int dt; unsigned long flags; - if (qas) - ppr_options |= MSG_EXT_PPR_QAS_REQ; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s QAS\n", ahd_name(ahd), + qas ? "enabling" : "disabling"); +#endif + + if (qas) { + ppr_options |= MSG_EXT_PPR_QAS_REQ; + } + + dt = ppr_options & MSG_EXT_PPR_DT_REQ; ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2474,16 +2529,29 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_IU_REQ; unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned int dt; unsigned long flags; - if (iu) +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s IU\n", ahd_name(ahd), + iu ? "enabling" : "disabling"); +#endif + + if (iu) { ppr_options |= MSG_EXT_PPR_IU_REQ; + ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */ + } + + dt = ppr_options & MSG_EXT_PPR_DT_REQ; ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2506,6 +2574,12 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Read Streaming\n", ahd_name(ahd), + rdstrm ? "enabling" : "disabling"); +#endif + if (rdstrm) ppr_options |= MSG_EXT_PPR_RD_STRM; @@ -2513,6 +2587,131 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_WR_FLOW; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Write Flow Control\n", ahd_name(ahd), + wrflow ? "enabling" : "disabling"); +#endif + + if (wrflow) + ppr_options |= MSG_EXT_PPR_WR_FLOW; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_rti(struct scsi_target *starget, int rti) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_RTI; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if ((ahd->features & AHD_RTI) == 0) { +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: RTI not available\n", ahd_name(ahd)); +#endif + return; + } + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s RTI\n", ahd_name(ahd), + rti ? "enabling" : "disabling"); +#endif + + if (rti) + ppr_options |= MSG_EXT_PPR_RTI; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_PCOMP_EN; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Precompensation\n", ahd_name(ahd), + pcomp ? "Enable" : "Disable"); +#endif + + if (pcomp) + ppr_options |= MSG_EXT_PPR_PCOMP_EN; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2534,6 +2733,12 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_qas = 1, .set_rd_strm = ahd_linux_set_rd_strm, .show_rd_strm = 1, + .set_wr_flow = ahd_linux_set_wr_flow, + .show_wr_flow = 1, + .set_rti = ahd_linux_set_rti, + .show_rti = 1, + .set_pcomp_en = ahd_linux_set_pcomp_en, + .show_pcomp_en = 1, }; -- cgit v1.2.3 From 3f40d7d6eaadecd48f6d1c0c4a5ad414b992260e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 13:25:10 -0500 Subject: [SCSI] aic79xx: fix up transport settings There's a slight problem in the way you've done the transport parameters; reading from the variables actually produces the current settings, not the ones you just set (and there's usually a lag because devices don't renegotiate until the next command goes over the bus). If you set the bit immediately, you get into the situation where the transport parameters report something as being set even if the drive cannot support it. I patched the driver to do it this way and also corrected a panic in the proc routines. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 39 +++++++++---------------------------- drivers/scsi/aic7xxx/aic79xx_proc.c | 4 ++-- 2 files changed, 11 insertions(+), 32 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index cf8e0ca830a..10a2570ca38 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1624,7 +1624,11 @@ ahd_send_async(struct ahd_softc *ahd, char channel, target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) - + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0); + + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0) + + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0) + + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0) + + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0) + + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0); if (tinfo->curr.period == spi_period(starget) && tinfo->curr.width == spi_width(starget) @@ -1639,6 +1643,10 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; + spi_rd_strm(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RD_STRM ? 1 : 0; + spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0; + spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0; + spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2318,18 +2326,6 @@ done: static void ahd_linux_exit(void); -static void ahd_linux_set_xferflags(struct scsi_target *starget, unsigned int ppr_options, unsigned int period) -{ - spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; - spi_dt(starget) = (ppr_options & MSG_EXT_PPR_DT_REQ)? 1 : 0; - spi_iu(starget) = (ppr_options & MSG_EXT_PPR_IU_REQ) ? 1 : 0; - spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; - spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; - spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; - spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; - spi_period(starget) = period; -} - static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2388,8 +2384,6 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2424,7 +2418,6 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); } - ahd_linux_set_xferflags(starget, ppr_options, period); ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, @@ -2467,8 +2460,6 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2508,8 +2499,6 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2550,8 +2539,6 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2588,8 +2575,6 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2626,8 +2611,6 @@ static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2672,8 +2655,6 @@ static void ahd_linux_set_rti(struct scsi_target *starget, int rti) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2710,8 +2691,6 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 2058aa9b5c8..cffdd104f9e 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -178,9 +178,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); starget = ahd->platform_data->starget[target_offset]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) return; + targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahd_format_transinfo(info, &tinfo->goal); -- cgit v1.2.3 From d872ebe4549576e7aab60ed7c746193196381dd0 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 15:43:52 -0500 Subject: [SCSI] add missing hold_mcs parameter to the spi transport class This parameter is important only to people who take the time to tune the margin control settings, otherwise it's completely irrelevant. However, just in case anyone should want to do this, it's appropriate to include the parameter. I don't do anything with it in DV by design, so the parameter will come up as off by default, so if anyone actually wants to play with the margin control settings they'll have to enable it under the spi_transport class first. I also updated the transfer settings display to report all of the PPR settings instead of only DT, IU and QAS Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 7670919a087..e7b9570c818 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -35,7 +35,7 @@ #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) -#define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ +#define SPI_NUM_ATTRS 14 /* increase this if you add attributes */ #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always * on" attributes */ #define SPI_HOST_ATTRS 1 @@ -231,6 +231,7 @@ static int spi_setup_transport_attrs(struct device *dev) spi_rd_strm(starget) = 0; spi_rti(starget) = 0; spi_pcomp_en(starget) = 0; + spi_hold_mcs(starget) = 0; spi_dv_pending(starget) = 0; spi_initial_dv(starget) = 0; init_MUTEX(&spi_dv_sem(starget)); @@ -347,6 +348,7 @@ spi_transport_rd_attr(wr_flow, "%d\n"); spi_transport_rd_attr(rd_strm, "%d\n"); spi_transport_rd_attr(rti, "%d\n"); spi_transport_rd_attr(pcomp_en, "%d\n"); +spi_transport_rd_attr(hold_mcs, "%d\n"); /* we only care about the first child device so we return 1 */ static int child_iter(struct device *dev, void *data) @@ -1028,10 +1030,17 @@ void spi_display_xfer_agreement(struct scsi_target *starget) sprint_frac(tmp, picosec, 1000); dev_info(&starget->dev, - "%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n", - scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10, - tp->dt ? "DT" : "ST", tp->iu ? " IU" : "", - tp->qas ? " QAS" : "", tmp, tp->offset); + "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)\n", + scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10, + tp->dt ? "DT" : "ST", + tp->iu ? " IU" : "", + tp->qas ? " QAS" : "", + tp->rd_strm ? " RDSTRM" : "", + tp->rti ? " RTI" : "", + tp->wr_flow ? " WRFLOW" : "", + tp->pcomp_en ? " PCOMP" : "", + tp->hold_mcs ? " HMCS" : "", + tmp, tp->offset); } else { dev_info(&starget->dev, "%sasynchronous.\n", tp->width ? "wide " : ""); @@ -1154,6 +1163,7 @@ spi_attach_transport(struct spi_function_template *ft) SETUP_ATTRIBUTE(rd_strm); SETUP_ATTRIBUTE(rti); SETUP_ATTRIBUTE(pcomp_en); + SETUP_ATTRIBUTE(hold_mcs); /* if you add an attribute but forget to increase SPI_NUM_ATTRS * this bug will trigger */ -- cgit v1.2.3 From 88ff29a4a5a8c4e0ecf375f783be071d1e7e264d Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 15:59:04 -0500 Subject: [SCSI] aic79xx: add hold_mcs to the transport parameters since this card can support the setting, add it to the parameter list. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 10a2570ca38..982a74a145f 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1628,7 +1628,8 @@ ahd_send_async(struct ahd_softc *ahd, char channel, + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0) + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0) + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0) - + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0); + + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0) + + (spi_hold_mcs(starget) ? MSG_EXT_PPR_HOLD_MCS : 0); if (tinfo->curr.period == spi_period(starget) && tinfo->curr.width == spi_width(starget) @@ -1647,6 +1648,7 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0; spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0; spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0; + spi_hold_mcs(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_HOLD_MCS ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2697,6 +2699,38 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) ahd_unlock(ahd, &flags); } +static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_HOLD_MCS; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (hold) + ppr_options |= MSG_EXT_PPR_HOLD_MCS; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + + + static struct spi_function_template ahd_linux_transport_functions = { .set_offset = ahd_linux_set_offset, .show_offset = 1, @@ -2718,6 +2752,8 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_rti = 1, .set_pcomp_en = ahd_linux_set_pcomp_en, .show_pcomp_en = 1, + .set_hold_mcs = ahd_linux_set_hold_mcs, + .show_hold_mcs = 1, }; -- cgit v1.2.3 From 52b5cfb355b2b3274979d25490f190d478ab1fad Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 4 Aug 2005 09:16:59 +0200 Subject: [SCSI] aic79xx: fixup DT setting this patch is just a cross-port of the fixup for aic7xxx DT settings. As the same restrictions apply for aic79xx also (DT requires wide transfers) the dt setting routine should be modified equivalently. And an invalid period setting will be caught by ahd_find_syncrate() anyway. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 982a74a145f..40f32bb2397 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2440,6 +2440,7 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_DT_REQ; unsigned int period = tinfo->goal.period; + unsigned int width = tinfo->goal.width; unsigned long flags; #ifdef AHD_DEBUG @@ -2449,8 +2450,8 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) #endif if (dt) { ppr_options |= MSG_EXT_PPR_DT_REQ; - if (period > 9) - period = 9; /* at least 12.5ns for DT */ + if (!width) + ahd_linux_set_width(starget, 1); } else { if (period <= 9) period = 10; /* If resetting DT, period must be >= 25ns */ -- cgit v1.2.3 From 79778a27be4c704552a18cf2a3e8b9e30623acd1 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 4 Aug 2005 17:33:22 -0500 Subject: [SCSI] aic7xxx: upport all sequencer and core fixes from adaptec version 6.3.9 This patch upports all relevant code fixes and bumps the driver version to 7.0 to signify starting a new tree. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx.h | 4 +- drivers/scsi/aic7xxx/aic7xxx.reg | 4 +- drivers/scsi/aic7xxx/aic7xxx.seq | 5 +- drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 36 +- drivers/scsi/aic7xxx/aic7xxx_core.c | 60 +- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 + drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 +- drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped | 6 +- drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped | 4 +- drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped | 933 ++++++++++++----------- 10 files changed, 544 insertions(+), 512 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 088cbc23743..91d294c6334 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $ * * $FreeBSD$ */ @@ -243,7 +243,7 @@ typedef enum { */ AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, AHC_AIC7860_FE = AHC_AIC7850_FE, - AHC_AIC7870_FE = AHC_TARGETMODE, + AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* * Although we have space for both the initiator and diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index 810ec700d9f..e196d83b93c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1306,7 +1306,6 @@ scratch_ram { */ MWI_RESIDUAL { size 1 - alias TARG_IMMEDIATE_SCB } /* * SCBID of the next SCB to be started by the controller. @@ -1461,6 +1460,7 @@ scratch_ram { */ LAST_MSG { size 1 + alias TARG_IMMEDIATE_SCB } /* diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq index d84b741fbab..15196390e28 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.seq +++ b/drivers/scsi/aic7xxx/aic7xxx.seq @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -679,6 +679,7 @@ await_busfree: clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ } and SXFRCTL0, ~SPIOEN; + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; mvi MISSED_BUSFREE call set_seqint; @@ -1097,7 +1098,7 @@ ultra2_dmahalt: test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz dma_last_sg; - if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { + if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { test DMAPARAMS, DIRECTION jz dma_mid_sg; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c index 468d612a44f..3cb07e114e8 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c +++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c @@ -28,9 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $ */ /* @@ -64,7 +62,6 @@ * is preceded by an initial zero (leading 0, followed by 16-bits, MSB * first). The clock cycling from low to high initiates the next data * bit to be sent from the chip. - * */ #ifdef __linux__ @@ -81,14 +78,22 @@ * Right now, we only have to read the SEEPROM. But we make it easier to * add other 93Cx6 functions. */ -static struct seeprom_cmd { +struct seeprom_cmd { uint8_t len; - uint8_t bits[9]; -} seeprom_read = {3, {1, 1, 0}}; + uint8_t bits[11]; +}; +/* Short opcodes for the c46 */ static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Long opcodes for the C56/C66 */ +static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Common opcodes */ static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; +static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; /* * Wait for the SEERDY to go high; about 800 ns. @@ -222,12 +227,25 @@ int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, u_int start_addr, u_int count) { + struct seeprom_cmd *ewen, *ewds; uint16_t v; uint8_t temp; int i, k; /* Place the chip into write-enable mode */ - send_seeprom_cmd(sd, &seeprom_ewen); + if (sd->sd_chip == C46) { + ewen = &seeprom_ewen; + ewds = &seeprom_ewds; + } else if (sd->sd_chip == C56_66) { + ewen = &seeprom_long_ewen; + ewds = &seeprom_long_ewds; + } else { + printf("ahc_write_seeprom: unsupported seeprom type %d\n", + sd->sd_chip); + return (0); + } + + send_seeprom_cmd(sd, ewen); reset_seeprom(sd); /* Write all requested data out to the seeprom. */ @@ -277,7 +295,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, } /* Put the chip back into write-protect mode */ - send_seeprom_cmd(sd, &seeprom_ewds); + send_seeprom_cmd(sd, ewds); reset_seeprom(sd); return (1); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 7bc01e41bcc..58ac46103eb 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -37,9 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $ */ #ifdef __linux__ @@ -287,10 +285,19 @@ ahc_restart(struct ahc_softc *ahc) ahc_outb(ahc, SEQ_FLAGS2, ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); } + + /* + * Clear any pending sequencer interrupt. It is no + * longer relevant since we're resetting the Program + * Counter. + */ + ahc_outb(ahc, CLRINT, CLRSEQINT); + ahc_outb(ahc, MWI_RESIDUAL, 0); ahc_outb(ahc, SEQCTL, ahc->seqctl); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); + ahc_unpause(ahc); } @@ -1174,19 +1181,20 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb_index); } #endif - /* - * Force a renegotiation with this target just in - * case the cable was pulled and will later be - * re-attached. The target may forget its negotiation - * settings with us should it attempt to reselect - * during the interruption. The target will not issue - * a unit attention in this case, so we must always - * renegotiate. - */ ahc_scb_devinfo(ahc, &devinfo, scb); - ahc_force_renegotiation(ahc, &devinfo); ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_freeze_devq(ahc, scb); + + /* + * Cancel any pending transactions on the device + * now that it seems to be missing. This will + * also revert us to async/narrow transfers until + * we can renegotiate with the device. + */ + ahc_handle_devreset(ahc, &devinfo, + CAM_SEL_TIMEOUT, + "Selection Timeout", + /*verbose_level*/1); } ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); @@ -3763,8 +3771,9 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHC_TRANS_CUR, /*paused*/TRUE); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + if (status != CAM_SEL_TIMEOUT) + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -4003,14 +4012,6 @@ ahc_reset(struct ahc_softc *ahc, int reinit) * to disturb the integrity of the bus. */ ahc_pause(ahc); - if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) { - /* - * The chip has not been initialized since - * PCI/EISA/VLB bus reset. Don't trust - * "left over BIOS data". - */ - ahc->flags |= AHC_NO_BIOS_INIT; - } sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -5036,14 +5037,23 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) ahc->flags |= AHC_ALL_INTERRUPTS; paused = FALSE; do { - if (paused) + if (paused) { ahc_unpause(ahc); + /* + * Give the sequencer some time to service + * any active selections. + */ + ahc_delay(500); + } ahc_intr(ahc); ahc_pause(ahc); paused = TRUE; ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO); - ahc_clear_critical_section(ahc); intstat = ahc_inb(ahc, INTSTAT); + if ((intstat & INT_PEND) == 0) { + ahc_clear_critical_section(ahc); + intstat = ahc_inb(ahc, INTSTAT); + } } while (--maxloops && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0) && ((intstat & INT_PEND) != 0 diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 116d0f51ca2..e39361ac6a4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -635,6 +635,8 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) targ->sdev[sdev->lun] = sdev; + spi_period(starget) = 0; + return 0; } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 0e47ac21754..c5299626924 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -265,7 +265,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#define AIC7XXX_DRIVER_VERSION "6.2.36" +#define AIC7XXX_DRIVER_VERSION "7.0" /*************************** Device Data Structures ***************************/ /* diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped index 7c1390ed117..2ce1febca20 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -1298,7 +1298,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define CMDSIZE_TABLE_TAIL 0x34 #define MWI_RESIDUAL 0x38 -#define TARG_IMMEDIATE_SCB 0x38 #define NEXT_QUEUED_SCB 0x39 @@ -1380,6 +1379,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define RETURN_2 0x52 #define LAST_MSG 0x53 +#define TARG_IMMEDIATE_SCB 0x53 #define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped index 9c713775d44..88bfd767c51 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ #include "aic7xxx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped index cf411368a87..4cee08521e7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped @@ -2,13 +2,13 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xee, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -21,15 +21,15 @@ static uint8_t seqprog[] = { 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x01, 0x51, 0x20, 0x31, 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x5e, + 0x00, 0x51, 0x14, 0x5e, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xc8, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xd8, 0x5e, + 0xc1, 0x6a, 0xda, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, @@ -49,10 +49,10 @@ static uint8_t seqprog[] = { 0x08, 0x6a, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -93,7 +93,7 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0x20, 0x41, 0x02, 0x57, 0xae, 0x00, 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xd8, 0x5e, + 0x61, 0x6a, 0xda, 0x5e, 0x08, 0x51, 0x20, 0x71, 0x02, 0x0b, 0xb2, 0x78, 0x00, 0x65, 0xae, 0x40, @@ -106,7 +106,7 @@ static uint8_t seqprog[] = { 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xd2, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -140,27 +140,27 @@ static uint8_t seqprog[] = { 0x80, 0x0b, 0xc4, 0x79, 0x12, 0x01, 0x02, 0x00, 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x40, 0x6a, 0x16, 0x00, - 0x80, 0x3e, 0x84, 0x5d, + 0x80, 0x3e, 0x86, 0x5d, 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x84, 0x5d, - 0x00, 0xab, 0x84, 0x5d, + 0x20, 0x6a, 0x86, 0x5d, + 0x00, 0xab, 0x86, 0x5d, 0x01, 0xa9, 0x78, 0x30, 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xae, 0x40, 0x10, 0x03, 0x3c, 0x69, 0x08, 0x3c, 0x5a, 0x69, 0x04, 0x3c, 0x92, 0x69, 0x02, 0x3c, 0x98, 0x69, 0x01, 0x3c, 0x44, 0x79, - 0xff, 0x6a, 0x70, 0x00, + 0xff, 0x6a, 0xa6, 0x00, 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xc0, 0x5e, - 0xff, 0x38, 0x30, 0x71, + 0x00, 0x6a, 0xc2, 0x5e, + 0xff, 0x53, 0x30, 0x71, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x38, 0x12, 0x5e, + 0x00, 0x53, 0x14, 0x5e, 0x00, 0x65, 0xea, 0x58, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0x18, 0x41, @@ -168,10 +168,10 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0xf2, 0x58, 0xfd, 0x57, 0xae, 0x08, 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x84, 0x5d, - 0x04, 0x6a, 0x84, 0x5d, + 0x02, 0x6a, 0x86, 0x5d, + 0x04, 0x6a, 0x86, 0x5d, 0x01, 0x03, 0x4c, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, @@ -182,13 +182,13 @@ static uint8_t seqprog[] = { 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x6e, 0x5d, + 0xc4, 0x6a, 0x70, 0x5d, 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x84, 0x5d, + 0x28, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x84, 0x5d, + 0x08, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x6e, 0x5d, + 0x84, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xf2, 0x58, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -208,16 +208,16 @@ static uint8_t seqprog[] = { 0xf7, 0x3c, 0x78, 0x08, 0x00, 0x65, 0x20, 0x41, 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x6e, 0x5d, - 0x00, 0x65, 0x56, 0x42, - 0xc4, 0x6a, 0x6e, 0x5d, + 0x04, 0xaa, 0x70, 0x5d, + 0x00, 0x65, 0x58, 0x42, + 0xc4, 0x6a, 0x70, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x84, 0x5d, + 0x00, 0xa8, 0x86, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x84, 0x5d, + 0x00, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x8a, 0x44, + 0x00, 0xbb, 0x8c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, @@ -227,31 +227,32 @@ static uint8_t seqprog[] = { 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xe0, 0x5d, + 0x1c, 0x6a, 0xe2, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x1a, 0x01, 0x02, 0x00, 0x80, 0x6a, 0x74, 0x00, 0x40, 0x6a, 0x78, 0x00, 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x56, 0x7a, - 0x80, 0x64, 0x9e, 0x73, - 0xa0, 0x64, 0x00, 0x74, - 0xc0, 0x64, 0xf4, 0x73, - 0xe0, 0x64, 0x30, 0x74, - 0x01, 0x6a, 0xd8, 0x5e, + 0xbf, 0x64, 0x58, 0x7a, + 0x80, 0x64, 0xa0, 0x73, + 0xa0, 0x64, 0x02, 0x74, + 0xc0, 0x64, 0xf6, 0x73, + 0xe0, 0x64, 0x32, 0x74, + 0x01, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xe6, 0x79, + 0xc0, 0x6a, 0x78, 0x00, + 0x09, 0x0c, 0xe8, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xd8, 0x5e, + 0xb1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -264,29 +265,29 @@ static uint8_t seqprog[] = { 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xdc, 0x7e, - 0x80, 0xeb, 0x06, 0x7a, + 0x08, 0xeb, 0xde, 0x7e, + 0x80, 0xeb, 0x08, 0x7a, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0x0a, 0x6a, + 0x08, 0xeb, 0x0c, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xdc, 0x6e, - 0x88, 0xeb, 0x20, 0x72, - 0x08, 0xeb, 0xdc, 0x6e, - 0x04, 0xea, 0x24, 0xe2, - 0x08, 0xee, 0xdc, 0x6e, + 0x80, 0xa3, 0xde, 0x6e, + 0x88, 0xeb, 0x22, 0x72, + 0x08, 0xeb, 0xde, 0x6e, + 0x04, 0xea, 0x26, 0xe2, + 0x08, 0xee, 0xde, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0x08, 0x5a, + 0x00, 0x65, 0x0a, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xdc, 0x7e, + 0x80, 0x94, 0xde, 0x7e, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0xa3, 0xbc, 0x5e, + 0x00, 0x65, 0xfc, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x34, 0x7a, + 0x80, 0xa3, 0x36, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x80, 0x93, 0x26, 0x01, @@ -294,162 +295,162 @@ static uint8_t seqprog[] = { 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xdc, 0x7e, - 0xff, 0x8d, 0x4a, 0x6a, - 0xff, 0x8e, 0x4a, 0x6a, + 0xff, 0x64, 0xde, 0x7e, + 0xff, 0x8d, 0x4c, 0x6a, + 0xff, 0x8e, 0x4c, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xdc, 0x56, + 0x00, 0x65, 0xde, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, 0x00, 0x8c, 0x18, 0x19, 0xff, 0x8d, 0x1a, 0x21, 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x5a, 0x7a, - 0x21, 0x6a, 0xd8, 0x5e, + 0xc0, 0x3c, 0x5c, 0x7a, + 0x21, 0x6a, 0xda, 0x5e, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x62, 0x6a, + 0x40, 0x3f, 0x64, 0x6a, 0x04, 0x3b, 0x76, 0x00, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x6a, 0x7a, - 0x51, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x82, 0x42, + 0x20, 0x3c, 0x6c, 0x7a, + 0x51, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x84, 0x42, 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xba, 0x5e, + 0x00, 0xb3, 0xbc, 0x5e, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xee, 0x5d, + 0xac, 0x6a, 0xf0, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xf2, 0x5d, - 0x00, 0x65, 0x3a, 0x5a, + 0xb3, 0x6a, 0xf4, 0x5d, + 0x00, 0x65, 0x3c, 0x5a, 0xfd, 0xa4, 0x48, 0x09, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x01, 0xa4, 0x94, 0x7a, + 0x00, 0x65, 0xe8, 0x5d, + 0x01, 0xa4, 0x96, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x8a, 0x7a, - 0x03, 0x9e, 0x8c, 0x6a, + 0x10, 0x0c, 0x8c, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xd8, 0x5e, + 0x91, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9a, 0x7a, + 0x80, 0xa3, 0x9c, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0xfc, 0xa8, 0x6a, - 0x80, 0x0b, 0x9e, 0x6a, - 0x10, 0x0c, 0x9e, 0x7a, - 0x20, 0x93, 0x9e, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0xfc, 0xaa, 0x6a, + 0x80, 0x0b, 0xa0, 0x6a, + 0x10, 0x0c, 0xa0, 0x7a, + 0x20, 0x93, 0xa0, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xb2, 0x7a, - 0x40, 0x0d, 0xc6, 0x6a, + 0x02, 0xfc, 0xb4, 0x7a, + 0x40, 0x0d, 0xc8, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xc6, 0x42, - 0x40, 0x0d, 0xb8, 0x6a, - 0x00, 0x65, 0x0e, 0x5a, - 0x00, 0x65, 0xaa, 0x42, - 0x80, 0xfc, 0xc2, 0x7a, - 0x80, 0xa4, 0xc2, 0x6a, + 0x00, 0x65, 0xc8, 0x42, + 0x40, 0x0d, 0xba, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x00, 0x65, 0xac, 0x42, + 0x80, 0xfc, 0xc4, 0x7a, + 0x80, 0xa4, 0xc4, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, 0x7f, 0xa3, 0x46, 0x09, - 0x04, 0x3b, 0xe2, 0x6a, + 0x04, 0x3b, 0xe4, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0xa4, 0xe0, 0x7a, - 0x01, 0xfc, 0xd6, 0x7a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x00, 0x65, 0x82, 0x42, - 0x01, 0x94, 0xe0, 0x7a, - 0x10, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0xa4, 0xe2, 0x7a, + 0x01, 0xfc, 0xd8, 0x7a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x00, 0x65, 0x84, 0x42, + 0x01, 0x94, 0xe2, 0x7a, + 0x10, 0x94, 0xe4, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xe6, 0x6a, + 0x28, 0x93, 0xe8, 0x6a, 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xee, 0x6a, + 0x02, 0xfc, 0xf0, 0x6a, 0x01, 0x14, 0x46, 0x31, 0xff, 0x6a, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0xfc, 0x6a, - 0x80, 0xa3, 0xfc, 0x7a, - 0x80, 0x0b, 0xfa, 0x7a, - 0x04, 0x3b, 0xfc, 0x7a, + 0xff, 0x38, 0xfe, 0x6a, + 0x80, 0xa3, 0xfe, 0x7a, + 0x80, 0x0b, 0xfc, 0x7a, + 0x04, 0x3b, 0xfe, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0x0b, 0x0a, 0x6b, - 0x10, 0x0c, 0xfe, 0x7a, - 0x04, 0x93, 0x08, 0x6b, - 0x01, 0x94, 0x06, 0x7b, - 0x10, 0x94, 0x08, 0x6b, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0x0b, 0x0c, 0x6b, + 0x10, 0x0c, 0x00, 0x7b, + 0x04, 0x93, 0x0a, 0x6b, + 0x01, 0x94, 0x08, 0x7b, + 0x10, 0x94, 0x0a, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x0c, 0x6b, - 0xff, 0x08, 0x5a, 0x6b, - 0xff, 0x09, 0x5a, 0x6b, - 0xff, 0x0a, 0x5a, 0x6b, - 0xff, 0x38, 0x28, 0x7b, + 0x38, 0x93, 0x0e, 0x6b, + 0xff, 0x08, 0x5c, 0x6b, + 0xff, 0x09, 0x5c, 0x6b, + 0xff, 0x0a, 0x5c, 0x6b, + 0xff, 0x38, 0x2a, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, - 0x00, 0x38, 0xe0, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, + 0x00, 0x38, 0xe2, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x54, 0x43, - 0x80, 0xa3, 0x2e, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x30, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x5a, 0x43, - 0x08, 0xeb, 0x34, 0x7b, - 0x00, 0x65, 0x0e, 0x5a, - 0x08, 0xeb, 0x30, 0x6b, + 0x00, 0x65, 0x5c, 0x43, + 0x08, 0xeb, 0x36, 0x7b, + 0x00, 0x65, 0x10, 0x5a, + 0x08, 0xeb, 0x32, 0x6b, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xba, 0x5e, + 0x00, 0x6a, 0xbc, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xf4, 0x5d, - 0x08, 0x6a, 0xe0, 0x5d, + 0xa4, 0x6a, 0xf6, 0x5d, + 0x08, 0x6a, 0xe2, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8c, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, + 0x00, 0xa3, 0xbc, 0x5e, 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x3a, 0x5a, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x3c, 0x5a, + 0x00, 0x65, 0xfc, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x80, 0x0b, 0x82, 0x6a, - 0x80, 0x0b, 0x62, 0x6b, - 0x01, 0x0c, 0x5c, 0x7b, - 0x10, 0x0c, 0x82, 0x7a, - 0x03, 0x9e, 0x82, 0x6a, - 0x00, 0x65, 0x04, 0x5a, - 0x00, 0x6a, 0xba, 0x5e, - 0x01, 0xa4, 0x82, 0x6b, - 0xff, 0x38, 0x78, 0x7b, + 0x00, 0x65, 0xe8, 0x5d, + 0x80, 0x0b, 0x84, 0x6a, + 0x80, 0x0b, 0x64, 0x6b, + 0x01, 0x0c, 0x5e, 0x7b, + 0x10, 0x0c, 0x84, 0x7a, + 0x03, 0x9e, 0x84, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x6a, 0xbc, 0x5e, + 0x01, 0xa4, 0x84, 0x6b, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x7a, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -461,16 +462,16 @@ static uint8_t seqprog[] = { 0x04, 0x3c, 0xcc, 0x79, 0xfb, 0x3c, 0x78, 0x08, 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0x8e, 0x6b, + 0x01, 0x0c, 0x90, 0x6b, 0x80, 0xba, 0x20, 0x79, 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, - 0x23, 0x6a, 0x84, 0x5d, - 0x01, 0x6a, 0x84, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, + 0x23, 0x6a, 0x86, 0x5d, + 0x01, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x20, 0x41, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xa2, 0x7b, - 0x21, 0x6a, 0xd8, 0x5e, + 0x80, 0x3c, 0xa4, 0x7b, + 0x21, 0x6a, 0xda, 0x5e, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -480,16 +481,16 @@ static uint8_t seqprog[] = { 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xc8, 0x53, + 0xa0, 0x6a, 0xca, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xf4, 0x5d, - 0x00, 0xbc, 0xe0, 0x5d, + 0xa0, 0x6a, 0xf6, 0x5d, + 0x00, 0xbc, 0xe2, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xe0, 0x43, + 0x00, 0x65, 0xe2, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -499,128 +500,128 @@ static uint8_t seqprog[] = { 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, 0x02, 0x93, 0x26, 0x01, 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xe6, 0x6b, - 0x10, 0x0c, 0xe2, 0x7b, - 0x01, 0x03, 0xe6, 0x6b, - 0x20, 0x93, 0xe8, 0x6b, - 0x04, 0x0b, 0xee, 0x6b, + 0x04, 0x0b, 0xe8, 0x6b, + 0x10, 0x0c, 0xe4, 0x7b, + 0x01, 0x03, 0xe8, 0x6b, + 0x20, 0x93, 0xea, 0x6b, + 0x04, 0x0b, 0xf0, 0x6b, 0x40, 0x3c, 0x78, 0x00, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xf0, 0x6b, + 0x38, 0x93, 0xf2, 0x6b, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x56, 0x6c, + 0x80, 0x3c, 0x58, 0x6c, 0x01, 0x06, 0x50, 0x31, 0x80, 0xb8, 0x70, 0x01, 0x00, 0x65, 0xcc, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x1c, 0x64, - 0x10, 0xb8, 0x40, 0x6c, + 0x80, 0x65, 0x1e, 0x64, + 0x10, 0xb8, 0x42, 0x6c, 0xc0, 0x3e, 0xca, 0x00, - 0x40, 0xb8, 0x0c, 0x6c, + 0x40, 0xb8, 0x0e, 0x6c, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x20, 0x7c, + 0x20, 0xb8, 0x22, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, - 0x00, 0xbb, 0x20, 0x44, - 0xff, 0x65, 0x20, 0x64, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, + 0x00, 0xbb, 0x22, 0x44, + 0xff, 0x65, 0x22, 0x64, + 0x00, 0x65, 0x42, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0xfc, 0x73, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0xfe, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x68, 0x5d, - 0x80, 0x64, 0xd8, 0x6c, - 0x04, 0x64, 0x9a, 0x74, - 0x02, 0x64, 0xaa, 0x74, - 0x00, 0x6a, 0x60, 0x74, - 0x03, 0x64, 0xc8, 0x74, - 0x23, 0x64, 0x48, 0x74, - 0x08, 0x64, 0x5c, 0x74, - 0x61, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0xd8, 0x5d, + 0x64, 0x6a, 0x6a, 0x5d, + 0x80, 0x64, 0xda, 0x6c, + 0x04, 0x64, 0x9c, 0x74, + 0x02, 0x64, 0xac, 0x74, + 0x00, 0x6a, 0x62, 0x74, + 0x03, 0x64, 0xca, 0x74, + 0x23, 0x64, 0x4a, 0x74, + 0x08, 0x64, 0x5e, 0x74, + 0x61, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0xda, 0x5d, 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x40, 0x44, - 0x80, 0x04, 0x5a, 0x7c, - 0x51, 0x6a, 0x5e, 0x5d, - 0x01, 0x51, 0x5a, 0x64, - 0x01, 0xa4, 0x52, 0x7c, - 0x80, 0xba, 0x5c, 0x6c, - 0x41, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x21, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x07, 0x6a, 0x54, 0x5d, + 0x00, 0x65, 0x42, 0x44, + 0x80, 0x04, 0x5c, 0x7c, + 0x51, 0x6a, 0x60, 0x5d, + 0x01, 0x51, 0x5c, 0x64, + 0x01, 0xa4, 0x54, 0x7c, + 0x80, 0xba, 0x5e, 0x6c, + 0x41, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x21, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x07, 0x6a, 0x56, 0x5d, 0x01, 0x06, 0xd4, 0x30, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x56, 0x7c, - 0xc0, 0x3c, 0x6a, 0x7c, - 0x80, 0x3c, 0x56, 0x6c, - 0xff, 0xa8, 0x6a, 0x6c, - 0x40, 0x3c, 0x56, 0x6c, - 0x10, 0xb8, 0x6e, 0x7c, - 0xa1, 0x6a, 0xd8, 0x5e, - 0x01, 0xb4, 0x74, 0x6c, - 0x02, 0xb4, 0x76, 0x6c, - 0x01, 0xa4, 0x76, 0x7c, - 0xff, 0xa8, 0x86, 0x7c, + 0x80, 0xb8, 0x58, 0x7c, + 0xc0, 0x3c, 0x6c, 0x7c, + 0x80, 0x3c, 0x58, 0x6c, + 0xff, 0xa8, 0x6c, 0x6c, + 0x40, 0x3c, 0x58, 0x6c, + 0x10, 0xb8, 0x70, 0x7c, + 0xa1, 0x6a, 0xda, 0x5e, + 0x01, 0xb4, 0x76, 0x6c, + 0x02, 0xb4, 0x78, 0x6c, + 0x01, 0xa4, 0x78, 0x7c, + 0xff, 0xa8, 0x88, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x5e, - 0xff, 0xa8, 0x86, 0x7c, - 0x71, 0x6a, 0xd8, 0x5e, - 0x40, 0x51, 0x86, 0x64, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0xbb, 0x14, 0x5e, + 0xff, 0xa8, 0x88, 0x7c, + 0x71, 0x6a, 0xda, 0x5e, + 0x40, 0x51, 0x88, 0x64, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x8a, 0x5c, + 0x00, 0xbb, 0x8c, 0x5c, 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xb6, 0xdd, - 0x00, 0x51, 0xc8, 0x5d, + 0x00, 0x6a, 0xb8, 0xdd, + 0x00, 0x51, 0xca, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x56, 0x6c, + 0xc0, 0x3c, 0x58, 0x6c, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xd4, 0x5e, + 0x00, 0x65, 0xd6, 0x5e, 0x20, 0xb8, 0xde, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x3f, 0xba, 0x7c, 0x08, - 0x00, 0xb9, 0xce, 0x5c, + 0x00, 0xb9, 0xd0, 0x5c, 0x00, 0x65, 0xde, 0x41, 0x01, 0x06, 0xd4, 0x30, 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x5c, 0x7c, - 0x01, 0xa4, 0xb8, 0x7c, + 0x20, 0x3c, 0x5e, 0x7c, + 0x01, 0xa4, 0xba, 0x7c, 0x01, 0xb4, 0x68, 0x01, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x04, 0x14, 0x58, 0x31, 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0xec, 0x5d, + 0xa0, 0x6a, 0xee, 0x5d, 0x00, 0x65, 0xcc, 0x41, 0xdf, 0x3c, 0x78, 0x08, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -631,102 +632,102 @@ static uint8_t seqprog[] = { 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xe6, 0x4c, + 0x00, 0x65, 0xe8, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xee, 0x54, + 0x00, 0x65, 0xf0, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xf8, 0x4c, + 0x00, 0x65, 0xfa, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x00, 0x55, + 0x00, 0x65, 0x02, 0x55, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x12, 0x75, - 0x00, 0x51, 0x8e, 0x5d, + 0xff, 0x51, 0x14, 0x75, + 0x00, 0x51, 0x90, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x34, 0x45, + 0x00, 0x65, 0x36, 0x45, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x34, 0x75, - 0x00, 0x65, 0xb0, 0x5e, + 0x00, 0x3e, 0x36, 0x75, + 0x00, 0x65, 0xb2, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x50, 0x65, + 0xe0, 0x3f, 0x52, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x50, 0x65, - 0x51, 0x6a, 0x5e, 0x5d, - 0x00, 0x51, 0x8e, 0x5d, - 0x51, 0x6a, 0x5e, 0x5d, + 0x20, 0x12, 0x52, 0x65, + 0x51, 0x6a, 0x60, 0x5d, + 0x00, 0x51, 0x90, 0x5d, + 0x51, 0x6a, 0x60, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x4e, 0x65, + 0x00, 0x3d, 0x50, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x4e, 0x65, + 0x00, 0x3e, 0x50, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x4e, 0x7d, + 0x04, 0xb8, 0x50, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x44, 0x6d, + 0x20, 0xb8, 0x46, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xce, 0x5c, + 0x00, 0x3d, 0xd0, 0x5c, 0x01, 0x64, 0x20, 0x31, 0xff, 0x6a, 0x78, 0x08, 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x5c, 0x7c, - 0xff, 0x6a, 0x54, 0x5d, - 0x00, 0x65, 0x5c, 0x44, - 0x00, 0x65, 0xb0, 0x5e, - 0x31, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, + 0x10, 0xb8, 0x5e, 0x7c, + 0xff, 0x6a, 0x56, 0x5d, + 0x00, 0x65, 0x5e, 0x44, + 0x00, 0x65, 0xb2, 0x5e, + 0x31, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x60, 0x45, + 0x81, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x62, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x60, 0x7d, - 0x04, 0x0c, 0x5a, 0x6d, + 0x01, 0x0c, 0x62, 0x7d, + 0x04, 0x0c, 0x5c, 0x6d, 0xe0, 0x03, 0x7e, 0x08, 0xe0, 0x3f, 0xcc, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x6e, 0x6d, + 0x01, 0x03, 0x70, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x7c, 0x75, - 0x40, 0x65, 0x7c, 0x7d, - 0x00, 0x65, 0x7c, 0x5d, + 0x00, 0x66, 0x7e, 0x75, + 0x40, 0x65, 0x7e, 0x7d, + 0x00, 0x65, 0x7e, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x86, 0x7d, + 0x02, 0x0b, 0x88, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x8a, 0x7d, + 0x02, 0x0b, 0x8c, 0x7d, 0xf7, 0x01, 0x02, 0x0c, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xae, 0x75, + 0xff, 0x41, 0xb0, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x9e, 0x45, - 0xff, 0xbf, 0xae, 0x75, + 0x00, 0x65, 0xa0, 0x45, + 0xff, 0xbf, 0xb0, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x98, 0x65, - 0xff, 0x52, 0xac, 0x75, + 0x00, 0xbb, 0x9a, 0x65, + 0xff, 0x52, 0xae, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -734,28 +735,28 @@ static uint8_t seqprog[] = { 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x46, + 0x00, 0x51, 0x14, 0x46, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, + 0x48, 0x6a, 0x08, 0x5e, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, - 0x01, 0x6a, 0xe0, 0x5d, + 0x48, 0x6a, 0x08, 0x5e, + 0x01, 0x6a, 0xe2, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xcc, 0x7d, + 0x80, 0xee, 0xce, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, - 0x81, 0x6a, 0xd8, 0x5e, - 0x01, 0x0c, 0xd8, 0x7d, - 0x04, 0x0c, 0xd6, 0x6d, + 0x00, 0x65, 0xaa, 0x46, + 0x81, 0x6a, 0xda, 0x5e, + 0x01, 0x0c, 0xda, 0x7d, + 0x04, 0x0c, 0xd8, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -774,7 +775,7 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x06, 0x46, + 0x00, 0x65, 0x08, 0x46, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -785,63 +786,63 @@ static uint8_t seqprog[] = { 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, + 0x44, 0x6a, 0x04, 0x5e, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x26, 0x7e, + 0x04, 0x3b, 0x28, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x22, 0x66, - 0x00, 0x65, 0x3e, 0x46, + 0xdc, 0xee, 0x24, 0x66, + 0x00, 0x65, 0x40, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x2e, 0x7e, + 0x80, 0xee, 0x30, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x32, 0x66, + 0x50, 0xee, 0x34, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x38, 0x66, + 0x88, 0xee, 0x3a, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x3c, 0x66, + 0xd8, 0xee, 0x3e, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x40, 0x6e, + 0x18, 0xee, 0x42, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, - 0x20, 0x6a, 0xe0, 0x5d, + 0x44, 0x6a, 0x04, 0x5e, + 0x20, 0x6a, 0xe2, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x5a, 0x6e, + 0x04, 0x3b, 0x5c, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x98, 0x5e, - 0x00, 0x65, 0x52, 0x66, + 0x00, 0x65, 0x9a, 0x5e, + 0x00, 0x65, 0x54, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, + 0x00, 0x65, 0xaa, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x5e, 0x6e, - 0x10, 0x94, 0x60, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, + 0x20, 0x94, 0x60, 0x6e, + 0x10, 0x94, 0x62, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, 0xff, 0x8c, 0xc8, 0x10, 0xc1, 0x64, 0xc8, 0x18, 0xf8, 0x64, 0xc8, 0x08, 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x6e, 0x66, - 0xc0, 0x66, 0xaa, 0x76, + 0x00, 0x66, 0x70, 0x66, + 0xc0, 0x66, 0xac, 0x76, 0x60, 0x66, 0xc8, 0x18, 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x5e, 0x46, + 0x00, 0x65, 0x60, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7c, 0x6e, + 0x08, 0x93, 0x7e, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xa8, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -858,11 +859,11 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xa8, 0x7e, + 0x08, 0x94, 0xaa, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xac, 0x6e, + 0x08, 0x93, 0xae, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xd4, 0x6e, + 0x04, 0xb8, 0xd6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, @@ -870,14 +871,14 @@ static uint8_t seqprog[] = { 0x01, 0x85, 0x0a, 0x01, 0x7f, 0x65, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xd0, 0x66, - 0xff, 0x41, 0xc8, 0x66, - 0xd1, 0x6a, 0xd8, 0x5e, + 0xff, 0x42, 0xd2, 0x66, + 0xff, 0x41, 0xca, 0x66, + 0xd1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x46, + 0x00, 0xbb, 0x14, 0x46, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -941,7 +942,7 @@ static ahc_patch_func_t ahc_patch17_func; static int ahc_patch17_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); + return ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0); } static ahc_patch_func_t ahc_patch16_func; @@ -1142,152 +1143,152 @@ static struct patch { { ahc_patch0_func, 196, 1, 1 }, { ahc_patch9_func, 212, 6, 2 }, { ahc_patch0_func, 218, 6, 1 }, - { ahc_patch8_func, 226, 20, 2 }, + { ahc_patch8_func, 226, 21, 2 }, { ahc_patch1_func, 241, 1, 1 }, - { ahc_patch1_func, 248, 1, 2 }, - { ahc_patch0_func, 249, 2, 2 }, - { ahc_patch11_func, 250, 1, 1 }, - { ahc_patch9_func, 258, 27, 3 }, - { ahc_patch1_func, 274, 10, 2 }, - { ahc_patch13_func, 277, 1, 1 }, - { ahc_patch14_func, 285, 14, 1 }, - { ahc_patch1_func, 301, 1, 2 }, - { ahc_patch0_func, 302, 1, 1 }, - { ahc_patch9_func, 305, 1, 1 }, - { ahc_patch13_func, 310, 1, 1 }, - { ahc_patch9_func, 311, 2, 2 }, - { ahc_patch0_func, 313, 4, 1 }, - { ahc_patch14_func, 317, 1, 1 }, - { ahc_patch15_func, 319, 2, 3 }, - { ahc_patch9_func, 319, 1, 2 }, - { ahc_patch0_func, 320, 1, 1 }, - { ahc_patch6_func, 325, 1, 2 }, - { ahc_patch0_func, 326, 1, 1 }, - { ahc_patch1_func, 330, 47, 11 }, - { ahc_patch6_func, 337, 2, 4 }, - { ahc_patch7_func, 337, 1, 1 }, - { ahc_patch8_func, 338, 1, 1 }, - { ahc_patch0_func, 339, 1, 1 }, - { ahc_patch16_func, 340, 1, 1 }, - { ahc_patch6_func, 356, 6, 3 }, - { ahc_patch16_func, 356, 5, 1 }, - { ahc_patch0_func, 362, 7, 1 }, - { ahc_patch13_func, 372, 5, 1 }, - { ahc_patch0_func, 377, 52, 17 }, - { ahc_patch14_func, 377, 1, 1 }, - { ahc_patch7_func, 379, 2, 2 }, - { ahc_patch17_func, 380, 1, 1 }, - { ahc_patch9_func, 383, 1, 1 }, - { ahc_patch18_func, 390, 1, 1 }, - { ahc_patch14_func, 395, 9, 3 }, - { ahc_patch9_func, 396, 3, 2 }, - { ahc_patch0_func, 399, 3, 1 }, - { ahc_patch9_func, 407, 6, 2 }, - { ahc_patch0_func, 413, 9, 2 }, - { ahc_patch13_func, 413, 1, 1 }, - { ahc_patch13_func, 422, 2, 1 }, - { ahc_patch14_func, 424, 1, 1 }, - { ahc_patch9_func, 426, 1, 2 }, - { ahc_patch0_func, 427, 1, 1 }, - { ahc_patch7_func, 428, 1, 1 }, + { ahc_patch1_func, 249, 1, 2 }, + { ahc_patch0_func, 250, 2, 2 }, + { ahc_patch11_func, 251, 1, 1 }, + { ahc_patch9_func, 259, 27, 3 }, + { ahc_patch1_func, 275, 10, 2 }, + { ahc_patch13_func, 278, 1, 1 }, + { ahc_patch14_func, 286, 14, 1 }, + { ahc_patch1_func, 302, 1, 2 }, + { ahc_patch0_func, 303, 1, 1 }, + { ahc_patch9_func, 306, 1, 1 }, + { ahc_patch13_func, 311, 1, 1 }, + { ahc_patch9_func, 312, 2, 2 }, + { ahc_patch0_func, 314, 4, 1 }, + { ahc_patch14_func, 318, 1, 1 }, + { ahc_patch15_func, 320, 2, 3 }, + { ahc_patch9_func, 320, 1, 2 }, + { ahc_patch0_func, 321, 1, 1 }, + { ahc_patch6_func, 326, 1, 2 }, + { ahc_patch0_func, 327, 1, 1 }, + { ahc_patch1_func, 331, 47, 11 }, + { ahc_patch6_func, 338, 2, 4 }, + { ahc_patch7_func, 338, 1, 1 }, + { ahc_patch8_func, 339, 1, 1 }, + { ahc_patch0_func, 340, 1, 1 }, + { ahc_patch16_func, 341, 1, 1 }, + { ahc_patch6_func, 357, 6, 3 }, + { ahc_patch16_func, 357, 5, 1 }, + { ahc_patch0_func, 363, 7, 1 }, + { ahc_patch13_func, 373, 5, 1 }, + { ahc_patch0_func, 378, 52, 17 }, + { ahc_patch14_func, 378, 1, 1 }, + { ahc_patch7_func, 380, 2, 2 }, + { ahc_patch17_func, 381, 1, 1 }, + { ahc_patch9_func, 384, 1, 1 }, + { ahc_patch18_func, 391, 1, 1 }, + { ahc_patch14_func, 396, 9, 3 }, + { ahc_patch9_func, 397, 3, 2 }, + { ahc_patch0_func, 400, 3, 1 }, + { ahc_patch9_func, 408, 6, 2 }, + { ahc_patch0_func, 414, 9, 2 }, + { ahc_patch13_func, 414, 1, 1 }, + { ahc_patch13_func, 423, 2, 1 }, + { ahc_patch14_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, { ahc_patch7_func, 429, 1, 1 }, - { ahc_patch8_func, 430, 3, 3 }, - { ahc_patch6_func, 431, 1, 2 }, - { ahc_patch0_func, 432, 1, 1 }, - { ahc_patch9_func, 433, 1, 1 }, - { ahc_patch15_func, 434, 1, 2 }, - { ahc_patch13_func, 434, 1, 1 }, - { ahc_patch14_func, 436, 9, 4 }, - { ahc_patch9_func, 436, 1, 1 }, - { ahc_patch9_func, 443, 2, 1 }, - { ahc_patch0_func, 445, 4, 3 }, - { ahc_patch9_func, 445, 1, 2 }, - { ahc_patch0_func, 446, 3, 1 }, - { ahc_patch1_func, 450, 2, 1 }, - { ahc_patch7_func, 452, 10, 2 }, - { ahc_patch0_func, 462, 1, 1 }, - { ahc_patch8_func, 463, 118, 22 }, - { ahc_patch1_func, 465, 3, 2 }, - { ahc_patch0_func, 468, 5, 3 }, - { ahc_patch9_func, 468, 2, 2 }, - { ahc_patch0_func, 470, 3, 1 }, - { ahc_patch1_func, 475, 2, 2 }, - { ahc_patch0_func, 477, 6, 3 }, - { ahc_patch9_func, 477, 2, 2 }, - { ahc_patch0_func, 479, 3, 1 }, - { ahc_patch1_func, 485, 2, 2 }, - { ahc_patch0_func, 487, 9, 7 }, - { ahc_patch9_func, 487, 5, 6 }, - { ahc_patch19_func, 487, 1, 2 }, - { ahc_patch0_func, 488, 1, 1 }, - { ahc_patch19_func, 490, 1, 2 }, - { ahc_patch0_func, 491, 1, 1 }, - { ahc_patch0_func, 492, 4, 1 }, - { ahc_patch6_func, 497, 3, 2 }, - { ahc_patch0_func, 500, 1, 1 }, - { ahc_patch6_func, 510, 1, 2 }, - { ahc_patch0_func, 511, 1, 1 }, - { ahc_patch20_func, 548, 7, 1 }, - { ahc_patch3_func, 583, 1, 2 }, - { ahc_patch0_func, 584, 1, 1 }, - { ahc_patch21_func, 587, 1, 1 }, - { ahc_patch8_func, 589, 106, 33 }, - { ahc_patch4_func, 591, 1, 1 }, - { ahc_patch1_func, 597, 2, 2 }, - { ahc_patch0_func, 599, 1, 1 }, - { ahc_patch1_func, 602, 1, 2 }, - { ahc_patch0_func, 603, 1, 1 }, - { ahc_patch9_func, 604, 3, 3 }, - { ahc_patch15_func, 605, 1, 1 }, - { ahc_patch0_func, 607, 4, 1 }, - { ahc_patch19_func, 616, 2, 2 }, - { ahc_patch0_func, 618, 1, 1 }, - { ahc_patch19_func, 622, 10, 3 }, - { ahc_patch5_func, 624, 8, 1 }, - { ahc_patch0_func, 632, 9, 2 }, - { ahc_patch5_func, 633, 8, 1 }, - { ahc_patch4_func, 643, 1, 2 }, - { ahc_patch0_func, 644, 1, 1 }, - { ahc_patch19_func, 645, 1, 2 }, - { ahc_patch0_func, 646, 3, 2 }, - { ahc_patch4_func, 648, 1, 1 }, - { ahc_patch5_func, 649, 1, 1 }, - { ahc_patch5_func, 652, 1, 1 }, - { ahc_patch5_func, 654, 1, 1 }, - { ahc_patch4_func, 656, 2, 2 }, - { ahc_patch0_func, 658, 2, 1 }, - { ahc_patch5_func, 660, 1, 1 }, - { ahc_patch5_func, 663, 1, 1 }, - { ahc_patch5_func, 666, 1, 1 }, - { ahc_patch19_func, 670, 1, 1 }, - { ahc_patch19_func, 673, 1, 1 }, - { ahc_patch4_func, 679, 1, 1 }, - { ahc_patch6_func, 682, 1, 2 }, - { ahc_patch0_func, 683, 1, 1 }, - { ahc_patch7_func, 695, 16, 1 }, - { ahc_patch4_func, 711, 20, 1 }, - { ahc_patch9_func, 732, 4, 2 }, - { ahc_patch0_func, 736, 4, 1 }, - { ahc_patch9_func, 740, 4, 2 }, - { ahc_patch0_func, 744, 3, 1 }, - { ahc_patch6_func, 750, 1, 1 }, - { ahc_patch22_func, 752, 14, 1 }, - { ahc_patch7_func, 766, 3, 1 }, - { ahc_patch9_func, 778, 24, 8 }, - { ahc_patch19_func, 782, 1, 2 }, - { ahc_patch0_func, 783, 1, 1 }, - { ahc_patch15_func, 788, 4, 2 }, - { ahc_patch0_func, 792, 7, 3 }, - { ahc_patch23_func, 792, 5, 2 }, - { ahc_patch0_func, 797, 2, 1 }, - { ahc_patch0_func, 802, 42, 3 }, - { ahc_patch18_func, 814, 18, 2 }, - { ahc_patch0_func, 832, 1, 1 }, - { ahc_patch4_func, 856, 1, 1 }, - { ahc_patch4_func, 857, 3, 2 }, - { ahc_patch0_func, 860, 1, 1 }, - { ahc_patch13_func, 861, 3, 1 }, - { ahc_patch4_func, 864, 12, 1 } + { ahc_patch7_func, 430, 1, 1 }, + { ahc_patch8_func, 431, 3, 3 }, + { ahc_patch6_func, 432, 1, 2 }, + { ahc_patch0_func, 433, 1, 1 }, + { ahc_patch9_func, 434, 1, 1 }, + { ahc_patch15_func, 435, 1, 2 }, + { ahc_patch13_func, 435, 1, 1 }, + { ahc_patch14_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 10, 2 }, + { ahc_patch0_func, 463, 1, 1 }, + { ahc_patch8_func, 464, 118, 22 }, + { ahc_patch1_func, 466, 3, 2 }, + { ahc_patch0_func, 469, 5, 3 }, + { ahc_patch9_func, 469, 2, 2 }, + { ahc_patch0_func, 471, 3, 1 }, + { ahc_patch1_func, 476, 2, 2 }, + { ahc_patch0_func, 478, 6, 3 }, + { ahc_patch9_func, 478, 2, 2 }, + { ahc_patch0_func, 480, 3, 1 }, + { ahc_patch1_func, 486, 2, 2 }, + { ahc_patch0_func, 488, 9, 7 }, + { ahc_patch9_func, 488, 5, 6 }, + { ahc_patch19_func, 488, 1, 2 }, + { ahc_patch0_func, 489, 1, 1 }, + { ahc_patch19_func, 491, 1, 2 }, + { ahc_patch0_func, 492, 1, 1 }, + { ahc_patch0_func, 493, 4, 1 }, + { ahc_patch6_func, 498, 3, 2 }, + { ahc_patch0_func, 501, 1, 1 }, + { ahc_patch6_func, 511, 1, 2 }, + { ahc_patch0_func, 512, 1, 1 }, + { ahc_patch20_func, 549, 7, 1 }, + { ahc_patch3_func, 584, 1, 2 }, + { ahc_patch0_func, 585, 1, 1 }, + { ahc_patch21_func, 588, 1, 1 }, + { ahc_patch8_func, 590, 106, 33 }, + { ahc_patch4_func, 592, 1, 1 }, + { ahc_patch1_func, 598, 2, 2 }, + { ahc_patch0_func, 600, 1, 1 }, + { ahc_patch1_func, 603, 1, 2 }, + { ahc_patch0_func, 604, 1, 1 }, + { ahc_patch9_func, 605, 3, 3 }, + { ahc_patch15_func, 606, 1, 1 }, + { ahc_patch0_func, 608, 4, 1 }, + { ahc_patch19_func, 617, 2, 2 }, + { ahc_patch0_func, 619, 1, 1 }, + { ahc_patch19_func, 623, 10, 3 }, + { ahc_patch5_func, 625, 8, 1 }, + { ahc_patch0_func, 633, 9, 2 }, + { ahc_patch5_func, 634, 8, 1 }, + { ahc_patch4_func, 644, 1, 2 }, + { ahc_patch0_func, 645, 1, 1 }, + { ahc_patch19_func, 646, 1, 2 }, + { ahc_patch0_func, 647, 3, 2 }, + { ahc_patch4_func, 649, 1, 1 }, + { ahc_patch5_func, 650, 1, 1 }, + { ahc_patch5_func, 653, 1, 1 }, + { ahc_patch5_func, 655, 1, 1 }, + { ahc_patch4_func, 657, 2, 2 }, + { ahc_patch0_func, 659, 2, 1 }, + { ahc_patch5_func, 661, 1, 1 }, + { ahc_patch5_func, 664, 1, 1 }, + { ahc_patch5_func, 667, 1, 1 }, + { ahc_patch19_func, 671, 1, 1 }, + { ahc_patch19_func, 674, 1, 1 }, + { ahc_patch4_func, 680, 1, 1 }, + { ahc_patch6_func, 683, 1, 2 }, + { ahc_patch0_func, 684, 1, 1 }, + { ahc_patch7_func, 696, 16, 1 }, + { ahc_patch4_func, 712, 20, 1 }, + { ahc_patch9_func, 733, 4, 2 }, + { ahc_patch0_func, 737, 4, 1 }, + { ahc_patch9_func, 741, 4, 2 }, + { ahc_patch0_func, 745, 3, 1 }, + { ahc_patch6_func, 751, 1, 1 }, + { ahc_patch22_func, 753, 14, 1 }, + { ahc_patch7_func, 767, 3, 1 }, + { ahc_patch9_func, 779, 24, 8 }, + { ahc_patch19_func, 783, 1, 2 }, + { ahc_patch0_func, 784, 1, 1 }, + { ahc_patch15_func, 789, 4, 2 }, + { ahc_patch0_func, 793, 7, 3 }, + { ahc_patch23_func, 793, 5, 2 }, + { ahc_patch0_func, 798, 2, 1 }, + { ahc_patch0_func, 803, 42, 3 }, + { ahc_patch18_func, 815, 18, 2 }, + { ahc_patch0_func, 833, 1, 1 }, + { ahc_patch4_func, 857, 1, 1 }, + { ahc_patch4_func, 858, 3, 2 }, + { ahc_patch0_func, 861, 1, 1 }, + { ahc_patch13_func, 862, 3, 1 }, + { ahc_patch4_func, 865, 12, 1 } }; static struct cs { @@ -1296,11 +1297,11 @@ static struct cs { } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 711, 727 }, - { 857, 860 }, - { 864, 870 }, - { 872, 874 }, - { 874, 876 } + { 712, 728 }, + { 858, 861 }, + { 865, 871 }, + { 873, 875 }, + { 875, 877 } }; static const int num_critical_sections = sizeof(critical_sections) -- cgit v1.2.3 From fc789a93994858b5e5a46afb96d0dcf6cc1b6f08 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 16:24:54 -0500 Subject: [SCSI] aic7xxx/79xx: fix another potential panic due to a non existent target I ran into this one sending bus resets across the hardware. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 ++-- drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 40f32bb2397..acaeebd5046 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1617,9 +1617,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, * are identical to those last reported. */ starget = ahd->platform_data->starget[target]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) break; + targ = scsi_transport_target_data(starget); target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index e39361ac6a4..3fbc10e58cc 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1618,9 +1618,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel, if (channel == 'B') target_offset += 8; starget = ahc->platform_data->starget[target_offset]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) break; + targ = scsi_transport_target_data(starget); target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) -- cgit v1.2.3 From bed30de47b034b5f28fb7db2fae4860b9d9c0622 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:38:51 -0700 Subject: [SCSI] aacraid: interupt mitigation Received from Mark Salyzyn from Adaptec: If more than two commands are outstanding to the controller, there is no need to notify the adapter via a PCI bus transaction of additional commands added into the queue; it will get to them when it works through the produce/consumer indexes. This reduced the PCI traffic in the driver to submit a command to the queue to near zero allowing a significant number of commands to be turned around with no need to block for the PCI bridge to flush the notify request to the adapter. Interrupt mitigation has always been present in the driver; it was turned off because of a bug that prevented one from realizing the usefulness of the feature. This bug is fixed in this patch. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/comminit.c | 4 +++- drivers/scsi/aacraid/commsup.c | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 43557bf661f..75abd045328 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -44,7 +44,9 @@ #include "aacraid.h" -struct aac_common aac_config; +struct aac_common aac_config = { + .irq_mod = 1 +}; static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 5322865942e..a1d303f0348 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -254,6 +254,7 @@ static void fib_dealloc(struct fib * fibptr) static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) { struct aac_queue * q; + unsigned long idx; /* * All of the queues wrap when they reach the end, so we check @@ -263,10 +264,23 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr */ q = &dev->queues->queue[qid]; - - *index = le32_to_cpu(*(q->headers.producer)); - if ((*index - 2) == le32_to_cpu(*(q->headers.consumer))) + + idx = *index = le32_to_cpu(*(q->headers.producer)); + /* Interrupt Moderation, only interrupt for first two entries */ + if (idx != le32_to_cpu(*(q->headers.consumer))) { + if (--idx == 0) { + if (qid == AdapHighCmdQueue) + idx = ADAP_HIGH_CMD_ENTRIES; + else if (qid == AdapNormCmdQueue) + idx = ADAP_NORM_CMD_ENTRIES; + else if (qid == AdapHighRespQueue) + idx = ADAP_HIGH_RESP_ENTRIES; + else if (qid == AdapNormRespQueue) + idx = ADAP_NORM_RESP_ENTRIES; + } + if (idx != le32_to_cpu(*(q->headers.consumer))) *nonotify = 1; + } if (qid == AdapHighCmdQueue) { if (*index >= ADAP_HIGH_CMD_ENTRIES) -- cgit v1.2.3 From c7f476023f57145357df32346b7de9202ce47d5f Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:38:55 -0700 Subject: [SCSI] aacraid: driver version update Received from Mark Salyzyn from Adaptec. Fixes a bug in check_revision. It should return the driver version not the firmware version. Update driver version number. Update driver version string. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aacraid.h | 8 +++++--- drivers/scsi/aacraid/commctrl.c | 18 ++++++++++++++---- drivers/scsi/aacraid/linit.c | 21 ++++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 3a11a536c0d..ddbbb85b3a7 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1512,11 +1512,12 @@ struct fib_ioctl struct revision { - u32 compat; - u32 version; - u32 build; + __le32 compat; + __le32 version; + __le32 build; }; + /* * Ugly - non Linux like ioctl coding for back compat. */ @@ -1737,3 +1738,4 @@ int aac_get_adapter_info(struct aac_dev* dev); int aac_send_shutdown(struct aac_dev *dev); extern int numacb; extern int acbsize; +extern char aac_driver_version[]; diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 85387099aab..8fceff9be1b 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -405,10 +405,20 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) static int check_revision(struct aac_dev *dev, void __user *arg) { struct revision response; - - response.compat = 1; - response.version = le32_to_cpu(dev->adapter_info.kernelrev); - response.build = le32_to_cpu(dev->adapter_info.kernelbuild); + char *driver_version = aac_driver_version; + u32 version; + + response.compat = cpu_to_le32(1); + version = (simple_strtol(driver_version, + &driver_version, 10) << 24) | 0x00000400; + version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; + version += simple_strtol(driver_version + 1, NULL, 10); + response.version = cpu_to_le32(version); +# if (defined(AAC_DRIVER_BUILD)) + response.build = cpu_to_le32(AAC_DRIVER_BUILD); +# else + response.build = cpu_to_le32(9999); +# endif if (copy_to_user(arg, &response, sizeof(response))) return -EFAULT; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index c1a4f978fcb..b6dda99f508 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -27,8 +27,11 @@ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller */ -#define AAC_DRIVER_VERSION "1.1.2-lk2" -#define AAC_DRIVER_BUILD_DATE __DATE__ +#define AAC_DRIVER_VERSION "1.1-4" +#ifndef AAC_DRIVER_BRANCH +#define AAC_DRIVER_BRANCH "" +#endif +#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__ #define AAC_DRIVERNAME "aacraid" #include @@ -58,16 +61,24 @@ #include "aacraid.h" +#ifdef AAC_DRIVER_BUILD +#define _str(x) #x +#define str(x) _str(x) +#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH +#else +#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE +#endif MODULE_AUTHOR("Red Hat Inc and Adaptec"); MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " "Adaptec Advanced Raid Products, " "and HP NetRAID-4M SCSI driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(AAC_DRIVER_VERSION); +MODULE_VERSION(AAC_DRIVER_FULL_VERSION); static LIST_HEAD(aac_devices); static int aac_cfg_major = -1; +char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; /* * Because of the way Linux names scsi devices, the order in this table has @@ -896,8 +907,8 @@ static int __init aac_init(void) { int error; - printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n", - AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE); + printk(KERN_INFO "Adaptec %s driver (%s)\n", + AAC_DRIVERNAME, aac_driver_version); error = pci_module_init(&aac_pci_driver); if (error) -- cgit v1.2.3 From bd1aac809ddbcf7772cfd809d8cfb29c729c6cf9 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:01 -0700 Subject: [SCSI] aacraid: driver shutdown method Add in pci shutdown method so that the adapter shuts down correctly and flushes its cache. Shutdown should also disable the adapter's interrupt when shutdown (in particularly if the driver is rmmod'd) to prevent spurious hardware activities. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aacraid.h | 4 ++++ drivers/scsi/aacraid/linit.c | 13 ++++++++++++- drivers/scsi/aacraid/rkt.c | 20 ++++++++++++++++++++ drivers/scsi/aacraid/rx.c | 20 ++++++++++++++++++++ drivers/scsi/aacraid/sa.c | 22 ++++++++++++++++++++-- 5 files changed, 76 insertions(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index ddbbb85b3a7..6f4906ee9a5 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -460,6 +460,7 @@ struct adapter_ops { void (*adapter_interrupt)(struct aac_dev *dev); void (*adapter_notify)(struct aac_dev *dev, u32 event); + void (*adapter_disable_int)(struct aac_dev *dev); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); }; @@ -994,6 +995,9 @@ struct aac_dev #define aac_adapter_notify(dev, event) \ (dev)->a_ops.adapter_notify(dev, event) +#define aac_adapter_disable_int(dev) \ + (dev)->a_ops.adapter_disable_int(dev) + #define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \ (dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index b6dda99f508..41255f7893d 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -849,11 +849,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, return 0; -out_deinit: + out_deinit: kill_proc(aac->thread_pid, SIGKILL, 0); wait_for_completion(&aac->aif_completion); aac_send_shutdown(aac); + aac_adapter_disable_int(aac); fib_map_free(aac); pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); kfree(aac->queues); @@ -870,6 +871,13 @@ out_deinit: return error; } +static void aac_shutdown(struct pci_dev *dev) +{ + struct Scsi_Host *shost = pci_get_drvdata(dev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + aac_send_shutdown(aac); +} + static void __devexit aac_remove_one(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -881,6 +889,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev) wait_for_completion(&aac->aif_completion); aac_send_shutdown(aac); + aac_adapter_disable_int(aac); fib_map_free(aac); pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); @@ -901,6 +910,7 @@ static struct pci_driver aac_pci_driver = { .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = __devexit_p(aac_remove_one), + .shutdown = aac_shutdown, }; static int __init aac_init(void) @@ -919,6 +929,7 @@ static int __init aac_init(void) printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n"); } + return 0; } diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 7d68b782513..557287a0b80 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -87,6 +87,16 @@ static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_rkt_disable_interrupt - Disable interrupts + * @dev: Adapter + */ + +static void aac_rkt_disable_interrupt(struct aac_dev *dev) +{ + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); +} + /** * rkt_sync_cmd - send a command and wait * @dev: Adapter @@ -412,10 +422,19 @@ int aac_rkt_init(struct aac_dev *dev) * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt; dev->a_ops.adapter_notify = aac_rkt_notify_adapter; dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; dev->a_ops.adapter_check_health = aac_rkt_check_health; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rkt_writeb(dev, MUnit.OIMR, 0xff); + rkt_writel(dev, MUnit.ODR, 0xffffffff); + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + if (aac_init_adapter(dev) == NULL) goto error_irq; /* @@ -438,6 +457,7 @@ error_kfree: kfree(dev->queues); error_irq: + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 1ff25f49fad..a8459faf87c 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -87,6 +87,16 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_rx_disable_interrupt - Disable interrupts + * @dev: Adapter + */ + +static void aac_rx_disable_interrupt(struct aac_dev *dev) +{ + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); +} + /** * rx_sync_cmd - send a command and wait * @dev: Adapter @@ -412,10 +422,19 @@ int aac_rx_init(struct aac_dev *dev) * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + if (aac_init_adapter(dev) == NULL) goto error_irq; /* @@ -438,6 +457,7 @@ error_kfree: kfree(dev->queues); error_irq: + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 0680249ab86..3900abc5850 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -81,6 +81,16 @@ static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_sa_disable_interrupt - disable interrupt + * @dev: Which adapter to enable. + */ + +static void aac_sa_disable_interrupt (struct aac_dev *dev) +{ + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); +} + /** * aac_sa_notify_adapter - handle adapter notification * @dev: Adapter that notification is for @@ -214,9 +224,8 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command, static void aac_sa_interrupt_adapter (struct aac_dev *dev) { - u32 ret; sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, - &ret, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } /** @@ -352,10 +361,18 @@ int aac_sa_init(struct aac_dev *dev) */ dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; + /* + * First clear out all interrupts. Then enable the one's that + * we can handle. + */ + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | + DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); if(aac_init_adapter(dev) == NULL) goto error_irq; @@ -381,6 +398,7 @@ error_kfree: kfree(dev->queues); error_irq: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: -- cgit v1.2.3 From e53cb35aaefb83de695e3fd305b9cfabd5bf8c86 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:09 -0700 Subject: [SCSI] aacraid: remove duplicate io callback code Received from Mark Salyzyn from Adaptec: This patch removes the duplicate code in the write_callback command completion handler, and renames read_callback to io_callback. Optimized the lba calculation into the debug print routine macro to optimize the i/o code path. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 63 +++++-------------------------------------- 1 file changed, 7 insertions(+), 56 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index ccdf440021f..b03c8dee76b 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -814,12 +814,11 @@ int aac_get_adapter_info(struct aac_dev* dev) } -static void read_callback(void *context, struct fib * fibptr) +static void io_callback(void *context, struct fib * fibptr) { struct aac_dev *dev; struct aac_read_reply *readreply; struct scsi_cmnd *scsicmd; - u32 lba; u32 cid; scsicmd = (struct scsi_cmnd *) context; @@ -827,8 +826,7 @@ static void read_callback(void *context, struct fib * fibptr) dev = (struct aac_dev *)scsicmd->device->host->hostdata; cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies)); + dprintk((KERN_DEBUG "io_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3], jiffies)); if (fibptr == NULL) BUG(); @@ -847,7 +845,7 @@ static void read_callback(void *context, struct fib * fibptr) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; else { #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "read_callback: io failed, status = %d\n", + printk(KERN_WARNING "io_callback: io failed, status = %d\n", le32_to_cpu(readreply->status)); #endif scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; @@ -867,53 +865,6 @@ static void read_callback(void *context, struct fib * fibptr) aac_io_done(scsicmd); } -static void write_callback(void *context, struct fib * fibptr) -{ - struct aac_dev *dev; - struct aac_write_reply *writereply; - struct scsi_cmnd *scsicmd; - u32 lba; - u32 cid; - - scsicmd = (struct scsi_cmnd *) context; - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); - - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies)); - if (fibptr == NULL) - BUG(); - - if(scsicmd->use_sg) - pci_unmap_sg(dev->pdev, - (struct scatterlist *)scsicmd->buffer, - scsicmd->use_sg, - scsicmd->sc_data_direction); - else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, - scsicmd->request_bufflen, - scsicmd->sc_data_direction); - - writereply = (struct aac_write_reply *) fib_data(fibptr); - if (le32_to_cpu(writereply->status) == ST_OK) - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - else { - printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - sizeof(struct sense_data)); - } - - fib_complete(fibptr); - fib_free(fibptr); - aac_io_done(scsicmd); -} - static int aac_read(struct scsi_cmnd * scsicmd, int cid) { u32 lba; @@ -978,7 +929,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) read_callback, + (fib_callback) io_callback, (void *) scsicmd); } else { struct aac_read *readcmd; @@ -1002,7 +953,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) read_callback, + (fib_callback) io_callback, (void *) scsicmd); } @@ -1085,7 +1036,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) write_callback, + (fib_callback) io_callback, (void *) scsicmd); } else { struct aac_write *writecmd; @@ -1111,7 +1062,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) write_callback, + (fib_callback) io_callback, (void *) scsicmd); } -- cgit v1.2.3 From 12a26d0879d8a4502425037e9013b1f64ed669b7 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:25 -0700 Subject: [SCSI] aacraid: aif registration timeout fix Received from Mark Salyzyn from Adaptec: If the Adapter is quiet and does not produce an AIF event packets to be picked up by the management applications for longer than the timeout interval of two minutes, the cleanup code that deals with aging out registrants could erroneously drop the registration. The timeout is there to clean up should the management application die and fail to poll for updated AIF event packets. Moving the timer update from the ioctl code that delivers an AIF to the polling registrant to the bottom of the ioctl means the timeout is reset with any management application polling activity regardless if an AIF is delivered or not removing the erroneous timeout cleanups. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/commctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 8fceff9be1b..71f1cad9b5f 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -287,7 +287,6 @@ return_fib: kfree(fib->hw_fib); kfree(fib); status = 0; - fibctx->jiffies = jiffies/HZ; } else { spin_unlock_irqrestore(&dev->fib_lock, flags); if (f.wait) { @@ -302,6 +301,7 @@ return_fib: status = -EAGAIN; } } + fibctx->jiffies = jiffies/HZ; return status; } -- cgit v1.2.3 From 0e68c00373f61fcdee453f6c9878e3390fc0f0ce Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:49 -0700 Subject: [SCSI] aacraid: sgraw command support Received from Mark Salyzyn from Adaptec: This patch adds support for the new raw io command. This new command offers much larger io commands, is more friendly to the internal firmware structure requiring less translation efforts by the firmware and offers support for targets greater than 2TB (patch to support >2TB will be sent in the future). Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 181 ++++++++++++++++++++++++++++++++++------- drivers/scsi/aacraid/aacraid.h | 43 +++++++++- 2 files changed, 194 insertions(+), 30 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index b03c8dee76b..d6c999cd7f7 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -133,6 +133,7 @@ struct inquiry_data { static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap); static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg); +static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg); static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); #ifdef AAC_DETAILED_STATUS_INFO static char *aac_get_status_string(u32 status); @@ -777,34 +778,36 @@ int aac_get_adapter_info(struct aac_dev* dev) /* * 57 scatter gather elements */ - dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgmap)) / - sizeof(struct sgmap); - if (dev->dac_support) { - /* - * 38 scatter gather elements - */ - dev->scsi_host_ptr->sg_tablesize = - (dev->max_fib_size - + if (!(dev->raw_io_interface)) { + dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write64) + - sizeof(struct sgmap64)) / - sizeof(struct sgmap64); - } - dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { - /* - * Worst case size that could cause sg overflow when - * we break up SG elements that are larger than 64KB. - * Would be nice if we could tell the SCSI layer what - * the maximum SG element size can be. Worst case is - * (sg_tablesize-1) 4KB elements with one 64KB - * element. - * 32bit -> 468 or 238KB 64bit -> 424 or 212KB - */ - dev->scsi_host_ptr->max_sectors = - (dev->scsi_host_ptr->sg_tablesize * 8) + 112; + sizeof(struct aac_write) + sizeof(struct sgmap)) / + sizeof(struct sgmap); + if (dev->dac_support) { + /* + * 38 scatter gather elements + */ + dev->scsi_host_ptr->sg_tablesize = + (dev->max_fib_size - + sizeof(struct aac_fibhdr) - + sizeof(struct aac_write64) + + sizeof(struct sgmap64)) / + sizeof(struct sgmap64); + } + dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; + if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { + /* + * Worst case size that could cause sg overflow when + * we break up SG elements that are larger than 64KB. + * Would be nice if we could tell the SCSI layer what + * the maximum SG element size can be. Worst case is + * (sg_tablesize-1) 4KB elements with one 64KB + * element. + * 32bit -> 468 or 238KB 64bit -> 424 or 212KB + */ + dev->scsi_host_ptr->max_sectors = + (dev->scsi_host_ptr->sg_tablesize * 8) + 112; + } } fib_complete(fibptr); @@ -905,7 +908,32 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fib_init(cmd_fibcontext); - if (dev->dac_support == 1) { + if (dev->raw_io_interface) { + struct aac_raw_io *readcmd; + readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); + readcmd->block[0] = cpu_to_le32(lba); + readcmd->block[1] = 0; + readcmd->count = cpu_to_le32(count<<9); + readcmd->cid = cpu_to_le16(cid); + readcmd->flags = cpu_to_le16(1); + readcmd->bpTotal = 0; + readcmd->bpComplete = 0; + + aac_build_sgraw(scsicmd, &readcmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw)); + if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) + BUG(); + /* + * Now send the Fib to the adapter + */ + status = fib_send(ContainerRawIo, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) scsicmd); + } else if (dev->dac_support == 1) { struct aac_read64 *readcmd; readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); readcmd->command = cpu_to_le32(VM_CtHostRead64); @@ -1012,7 +1040,32 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) } fib_init(cmd_fibcontext); - if(dev->dac_support == 1) { + if (dev->raw_io_interface) { + struct aac_raw_io *writecmd; + writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); + writecmd->block[0] = cpu_to_le32(lba); + writecmd->block[1] = 0; + writecmd->count = cpu_to_le32(count<<9); + writecmd->cid = cpu_to_le16(cid); + writecmd->flags = 0; + writecmd->bpTotal = 0; + writecmd->bpComplete = 0; + + aac_build_sgraw(scsicmd, &writecmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw)); + if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) + BUG(); + /* + * Now send the Fib to the adapter + */ + status = fib_send(ContainerRawIo, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) scsicmd); + } else if (dev->dac_support == 1) { struct aac_write64 *writecmd; writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); writecmd->command = cpu_to_le32(VM_CtHostWrite64); @@ -2028,6 +2081,76 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p return byte_count; } +static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg) +{ + struct Scsi_Host *host = scsicmd->device->host; + struct aac_dev *dev = (struct aac_dev *)host->hostdata; + unsigned long byte_count = 0; + + // Get rid of old data + psg->count = 0; + psg->sg[0].next = 0; + psg->sg[0].prev = 0; + psg->sg[0].addr[0] = 0; + psg->sg[0].addr[1] = 0; + psg->sg[0].count = 0; + psg->sg[0].flags = 0; + if (scsicmd->use_sg) { + struct scatterlist *sg; + int i; + int sg_count; + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsicmd->sc_data_direction); + + for (i = 0; i < sg_count; i++) { + int count = sg_dma_len(sg); + u64 addr = sg_dma_address(sg); + psg->sg[i].next = 0; + psg->sg[i].prev = 0; + psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); + psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + psg->sg[i].count = cpu_to_le32(count); + psg->sg[i].flags = 0; + byte_count += count; + sg++; + } + psg->count = cpu_to_le32(sg_count); + /* hba wants the size to be exact */ + if(byte_count > scsicmd->request_bufflen){ + u32 temp = le32_to_cpu(psg->sg[i-1].count) - + (byte_count - scsicmd->request_bufflen); + psg->sg[i-1].count = cpu_to_le32(temp); + byte_count = scsicmd->request_bufflen; + } + /* Check for command underflow */ + if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); + } + } + else if(scsicmd->request_bufflen) { + int count; + u64 addr; + scsicmd->SCp.dma_handle = pci_map_single(dev->pdev, + scsicmd->request_buffer, + scsicmd->request_bufflen, + scsicmd->sc_data_direction); + addr = scsicmd->SCp.dma_handle; + count = scsicmd->request_bufflen; + psg->count = cpu_to_le32(1); + psg->sg[0].next = 0; + psg->sg[0].prev = 0; + psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32)); + psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + psg->sg[0].count = cpu_to_le32(count); + psg->sg[0].flags = 0; + byte_count = scsicmd->request_bufflen; + } + return byte_count; +} + #ifdef AAC_DETAILED_STATUS_INFO struct aac_srb_status_info { diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 6f4906ee9a5..bc91e7ce5e5 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -114,6 +114,22 @@ struct user_sgentry64 { u32 count; /* Length. */ }; +struct sgentryraw { + __le32 next; /* reserved for F/W use */ + __le32 prev; /* reserved for F/W use */ + __le32 addr[2]; + __le32 count; + __le32 flags; /* reserved for F/W use */ +}; + +struct user_sgentryraw { + u32 next; /* reserved for F/W use */ + u32 prev; /* reserved for F/W use */ + u32 addr[2]; + u32 count; + u32 flags; /* reserved for F/W use */ +}; + /* * SGMAP * @@ -141,6 +157,16 @@ struct user_sgmap64 { struct user_sgentry64 sg[1]; }; +struct sgmapraw { + __le32 count; + struct sgentryraw sg[1]; +}; + +struct user_sgmapraw { + u32 count; + struct user_sgentryraw sg[1]; +}; + struct creation_info { u8 buildnum; /* e.g., 588 */ @@ -355,6 +381,7 @@ struct hw_fib { */ #define ContainerCommand 500 #define ContainerCommand64 501 +#define ContainerRawIo 502 /* * Cluster Commands */ @@ -986,6 +1013,9 @@ struct aac_dev u8 nondasd_support; u8 dac_support; u8 raid_scsi_mode; + /* macro side-effects BEWARE */ +# define raw_io_interface \ + init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4) u8 printf_enabled; }; @@ -1164,6 +1194,17 @@ struct aac_write_reply __le32 committed; }; +struct aac_raw_io +{ + __le32 block[2]; + __le32 count; + __le16 cid; + __le16 flags; /* 00 W, 01 R */ + __le16 bpTotal; /* reserved for F/W use */ + __le16 bpComplete; /* reserved for F/W use */ + struct sgmapraw sg; +}; + #define CT_FLUSH_CACHE 129 struct aac_synchronize { __le32 command; /* VM_ContainerConfig */ @@ -1204,7 +1245,7 @@ struct aac_srb }; /* - * This and assocated data structs are used by the + * This and associated data structs are used by the * ioctl caller and are in cpu order. */ struct user_aac_srb -- cgit v1.2.3 From a2ae85df80a5b996a05d6d2ffc9bf97797e93ec6 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sat, 6 Aug 2005 23:32:07 -0700 Subject: [SCSI] aic79xx: needs to select SPI_TRANSPORT_ATTRS without it you get this failure: drivers/built-in.o(.text+0xdcccd): In function `ahd_linux_slave_configure': drivers/scsi/aic7xxx/aic79xx_osm.c:636: undefined reference to `spi_dv_device' drivers/built-in.o(.text+0xdd7b1): In function `ahd_send_async': drivers/scsi/aic7xxx/aic79xx_osm.c:1652: undefined reference to `spi_display_xfer_agreement' drivers/built-in.o(.init.text+0x7b4d): In function `ahd_linux_init': drivers/scsi/aic7xxx/aic79xx_osm.c:2765: undefined reference to `spi_attach_transport' drivers/built-in.o(.init.text+0x7c94):drivers/scsi/aic7xxx/aic79xx_osm.c:2774: undefined reference to `spi_release_transport' drivers/built-in.o(.exit.text+0x72c): In function `ahd_linux_exit': drivers/scsi/aic7xxx/aic79xx_osm.c:2783: undefined reference to `spi_release_transport' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/Kconfig.aic79xx | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index c2523a30a7f..69ed77fcb71 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -5,6 +5,7 @@ config SCSI_AIC79XX tristate "Adaptec AIC79xx U320 support" depends on PCI && SCSI + select SCSI_SPI_ATTRS help This driver supports all of Adaptec's Ultra 320 PCI-X based SCSI controllers. -- cgit v1.2.3 From 5262d0851cc6692390ee1aa2c55f57f3bfd0a7c7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 16:31:35 -0500 Subject: [SCSI] aacraid: correct use of cmd->timeout field The cmd->timeout field has been obsolete for a while now. While looking to remove it, I came across this use in the aacraid driver. It looks like you want to initialise the firmware with the current timeout of the command (in seconds), so the value I think you should be using is cmd->timeout_per_command. Acked by: Mark Haverkamp Acked by: Mark Salyzyn Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index d6c999cd7f7..8e349358729 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1898,7 +1898,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) srbcmd->id = cpu_to_le32(scsicmd->device->id); srbcmd->lun = cpu_to_le32(scsicmd->device->lun); srbcmd->flags = cpu_to_le32(flag); - timeout = (scsicmd->timeout-jiffies)/HZ; + timeout = scsicmd->timeout_per_command/HZ; if(timeout == 0){ timeout = 1; } -- cgit v1.2.3 From f03a567054fea4f9d43c50ec91338266c0bd588d Mon Sep 17 00:00:00 2001 From: Kai Makisara Date: Tue, 2 Aug 2005 13:40:47 +0300 Subject: [SCSI] drivers/scsi/st.c: add reference count and related fixes I have rediffed the patch against 2.6.13-rc5, done a couple of cosmetic cleanups, and run some tests. Brian King has acknowledged that it fixes the problems he has seen. Seems mature enough for inclusion into 2.6.14 (or later)? Nate's explanation of the changes: I've attached patches against 2.6.13rc2. These are basically identical to my earlier patches, as I found that all issues I'd seen in earlier kernels still existed in this kernel. To summarize, the changes are: (more details in my original email) - add a kref to the scsi_tape structure, and associate reference counting stuff - set sr_request->end_io = blk_end_sync_rq so we get notified when an IO is rejected when the device goes away - check rq_status when IOs complete, else we don't know that IOs rejected for a dead device in fact did not complete - change last_SRpnt so it's set before an async IO is issued (in case st_sleep_done is bypassed) - fix a bogus use of last_SRpnt in st_chk_result Signed-off-by: Nate Dailey Signed-off-by: Kai Makisara Signed-off-by: James Bottomley --- drivers/scsi/st.c | 150 +++++++++++++++++++++++++++++++++++++++++++----------- drivers/scsi/st.h | 3 +- 2 files changed, 123 insertions(+), 30 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0291a8fb654..47a5698a712 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20050501"; +static char *verstr = "20050802"; #include @@ -219,6 +219,12 @@ static int switch_partition(struct scsi_tape *); static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); +static void scsi_tape_release(struct kref *); + +#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) + +static DECLARE_MUTEX(st_ref_sem); + #include "osst_detect.h" #ifndef SIGS_FROM_OSST @@ -230,6 +236,46 @@ static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); {"OnStream", "FW-", "", "osst"} #endif +static struct scsi_tape *scsi_tape_get(int dev) +{ + struct scsi_tape *STp = NULL; + + down(&st_ref_sem); + write_lock(&st_dev_arr_lock); + + if (dev < st_dev_max && scsi_tapes != NULL) + STp = scsi_tapes[dev]; + if (!STp) goto out; + + kref_get(&STp->kref); + + if (!STp->device) + goto out_put; + + if (scsi_device_get(STp->device)) + goto out_put; + + goto out; + +out_put: + kref_put(&STp->kref, scsi_tape_release); + STp = NULL; +out: + write_unlock(&st_dev_arr_lock); + up(&st_ref_sem); + return STp; +} + +static void scsi_tape_put(struct scsi_tape *STp) +{ + struct scsi_device *sdev = STp->device; + + down(&st_ref_sem); + kref_put(&STp->kref, scsi_tape_release); + scsi_device_put(sdev); + up(&st_ref_sem); +} + struct st_reject_data { char *vendor; char *model; @@ -311,7 +357,7 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt) return 0; cmdstatp = &STp->buffer->cmdstat; - st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp); + st_analyze_sense(SRpnt, cmdstatp); if (cmdstatp->have_sense) scode = STp->buffer->cmdstat.sense_hdr.sense_key; @@ -399,10 +445,10 @@ static void st_sleep_done(struct scsi_cmnd * SCpnt) (STp->buffer)->cmdstat.midlevel_result = SCpnt->result; SCpnt->request->rq_status = RQ_SCSI_DONE; - (STp->buffer)->last_SRpnt = SCpnt->sc_request; DEB( STp->write_pending = 0; ) - complete(SCpnt->request->waiting); + if (SCpnt->request->waiting) + complete(SCpnt->request->waiting); } /* Do the scsi command. Waits until command performed if do_wait is true. @@ -412,8 +458,20 @@ static struct scsi_request * st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) { + struct completion *waiting; unsigned char *bp; + /* if async, make sure there's no command outstanding */ + if (!do_wait && ((STp->buffer)->last_SRpnt)) { + printk(KERN_ERR "%s: Async command already active.\n", + tape_name(STp)); + if (signal_pending(current)) + (STp->buffer)->syscall_result = (-EINTR); + else + (STp->buffer)->syscall_result = (-EBUSY); + return NULL; + } + if (SRpnt == NULL) { SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC); if (SRpnt == NULL) { @@ -427,7 +485,13 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c } } - init_completion(&STp->wait); + /* If async IO, set last_SRpnt. This ptr tells write_behind_check + which IO is outstanding. It's nulled out when the IO completes. */ + if (!do_wait) + (STp->buffer)->last_SRpnt = SRpnt; + + waiting = &STp->wait; + init_completion(waiting); SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length); if (SRpnt->sr_use_sg) { if (!STp->buffer->do_dio) @@ -438,17 +502,20 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request->waiting = &(STp->wait); + SRpnt->sr_request->waiting = waiting; SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; SRpnt->sr_request->rq_disk = STp->disk; + SRpnt->sr_request->end_io = blk_end_sync_rq; STp->buffer->cmdstat.have_sense = 0; scsi_do_req(SRpnt, (void *) cmd, bp, bytes, st_sleep_done, timeout, retries); if (do_wait) { - wait_for_completion(SRpnt->sr_request->waiting); + wait_for_completion(waiting); SRpnt->sr_request->waiting = NULL; + if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE) + SRpnt->sr_result |= (DRIVER_ERROR << 24); (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); } return SRpnt; @@ -465,6 +532,7 @@ static int write_behind_check(struct scsi_tape * STp) struct st_buffer *STbuffer; struct st_partstat *STps; struct st_cmdstatus *cmdstatp; + struct scsi_request *SRpnt; STbuffer = STp->buffer; if (!STbuffer->writing) @@ -478,10 +546,14 @@ static int write_behind_check(struct scsi_tape * STp) ) /* end DEB */ wait_for_completion(&(STp->wait)); - (STp->buffer)->last_SRpnt->sr_request->waiting = NULL; + SRpnt = STbuffer->last_SRpnt; + STbuffer->last_SRpnt = NULL; + SRpnt->sr_request->waiting = NULL; + if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE) + SRpnt->sr_result |= (DRIVER_ERROR << 24); - (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); - scsi_release_request((STp->buffer)->last_SRpnt); + (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); + scsi_release_request(SRpnt); STbuffer->buffer_bytes -= STbuffer->writing; STps = &(STp->ps[STp->partition]); @@ -1055,25 +1127,20 @@ static int st_open(struct inode *inode, struct file *filp) */ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); + if (!(STp = scsi_tape_get(dev))) + return -ENXIO; + write_lock(&st_dev_arr_lock); - if (dev >= st_dev_max || scsi_tapes == NULL || - ((STp = scsi_tapes[dev]) == NULL)) { - write_unlock(&st_dev_arr_lock); - return (-ENXIO); - } filp->private_data = STp; name = tape_name(STp); if (STp->in_use) { write_unlock(&st_dev_arr_lock); + scsi_tape_put(STp); DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } - if(scsi_device_get(STp->device)) { - write_unlock(&st_dev_arr_lock); - return (-ENXIO); - } STp->in_use = 1; write_unlock(&st_dev_arr_lock); STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; @@ -1118,7 +1185,7 @@ static int st_open(struct inode *inode, struct file *filp) err_out: normalize_buffer(STp->buffer); STp->in_use = 0; - scsi_device_put(STp->device); + scsi_tape_put(STp); return retval; } @@ -1250,7 +1317,7 @@ static int st_release(struct inode *inode, struct file *filp) write_lock(&st_dev_arr_lock); STp->in_use = 0; write_unlock(&st_dev_arr_lock); - scsi_device_put(STp->device); + scsi_tape_put(STp); return result; } @@ -3887,6 +3954,7 @@ static int st_probe(struct device *dev) goto out_put_disk; } memset(tpnt, 0, sizeof(struct scsi_tape)); + kref_init(&tpnt->kref); tpnt->disk = disk; sprintf(disk->disk_name, "st%d", i); disk->private_data = &tpnt->driver; @@ -3902,6 +3970,7 @@ static int st_probe(struct device *dev) tpnt->tape_type = MT_ISSCSI2; tpnt->buffer = buffer; + tpnt->buffer->last_SRpnt = NULL; tpnt->inited = 0; tpnt->dirty = 0; @@ -4076,15 +4145,10 @@ static int st_remove(struct device *dev) tpnt->modes[mode].cdevs[j] = NULL; } } - tpnt->device = NULL; - if (tpnt->buffer) { - tpnt->buffer->orig_frp_segs = 0; - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer); - } - put_disk(tpnt->disk); - kfree(tpnt); + down(&st_ref_sem); + kref_put(&tpnt->kref, scsi_tape_release); + up(&st_ref_sem); return 0; } } @@ -4093,6 +4157,34 @@ static int st_remove(struct device *dev) return 0; } +/** + * scsi_tape_release - Called to free the Scsi_Tape structure + * @kref: pointer to embedded kref + * + * st_ref_sem must be held entering this routine. Because it is + * called on last put, you should always use the scsi_tape_get() + * scsi_tape_put() helpers which manipulate the semaphore directly + * and never do a direct kref_put(). + **/ +static void scsi_tape_release(struct kref *kref) +{ + struct scsi_tape *tpnt = to_scsi_tape(kref); + struct gendisk *disk = tpnt->disk; + + tpnt->device = NULL; + + if (tpnt->buffer) { + tpnt->buffer->orig_frp_segs = 0; + normalize_buffer(tpnt->buffer); + kfree(tpnt->buffer); + } + + disk->private_data = NULL; + put_disk(disk); + kfree(tpnt); + return; +} + static void st_intr(struct scsi_cmnd *SCpnt) { scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1); diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 061da111398..790acac160b 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -3,7 +3,7 @@ #define _ST_H #include - +#include /* Descriptor for analyzed sense data */ struct st_cmdstatus { @@ -156,6 +156,7 @@ struct scsi_tape { unsigned char last_sense[16]; #endif struct gendisk *disk; + struct kref kref; }; /* Bit masks for use_pf */ -- cgit v1.2.3 From b21a41385118f9a6af3cd96ce71090c5ada52eb5 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 21:45:40 -0500 Subject: [SCSI] add global timeout to the scsi mid-layer There are certain rogue devices (and the aic7xxx driver) that return BUSY or QUEUE_FULL forever. This code will apply a global timeout (of the total number of retries times the per command timer) to a given command. If it is exceeded, the command is completed regardless of its state. The patch also removes the unused field in the command: timeout and timeout_total. This solves the problem of detecting an endless loop in the mid-layer because of BUSY/QUEUE_FULL bouncing, but will not recover the device. In the aic7xxx case, the driver can be recovered by sending a bus reset, so possibly this should be tied into the error handler? Signed-off-by: James Bottomley --- drivers/scsi/advansys.c | 4 ++-- drivers/scsi/scsi.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 0fb93363eb2..37ec5411e32 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -9200,8 +9200,8 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s) (unsigned) s->serial_number, s->retries, s->allowed); printk( -" timeout_per_command %d, timeout_total %d, timeout %d\n", - s->timeout_per_command, s->timeout_total, s->timeout); +" timeout_per_command %d\n", + s->timeout_per_command); printk( " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d1aa95d45a7..4befbc275f9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -268,6 +268,7 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) } else put_device(&dev->sdev_gendev); + cmd->jiffies_at_alloc = jiffies; return cmd; } EXPORT_SYMBOL(scsi_get_command); @@ -798,9 +799,23 @@ static void scsi_softirq(struct softirq_action *h) while (!list_empty(&local_q)) { struct scsi_cmnd *cmd = list_entry(local_q.next, struct scsi_cmnd, eh_entry); + /* The longest time any command should be outstanding is the + * per command timeout multiplied by the number of retries. + * + * For a typical command, this is 2.5 minutes */ + unsigned long wait_for + = cmd->allowed * cmd->timeout_per_command; list_del_init(&cmd->eh_entry); disposition = scsi_decide_disposition(cmd); + if (disposition != SUCCESS && + time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { + dev_printk(KERN_ERR, &cmd->device->sdev_gendev, + "timing out command, waited %ds\n", + wait_for/HZ); + disposition = SUCCESS; + } + scsi_log_completion(cmd, disposition); switch (disposition) { case SUCCESS: -- cgit v1.2.3 From 8e87c2f118d40d2dc2f5d0140818e8cd023b13e1 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Mon, 8 Aug 2005 14:20:43 -0700 Subject: [SCSI] aacraid: adapter support update Received from Mark Salyzyn This patch adds the product ID for the ICP9067MA adapter. The entries for the ICP9085LI, ICP5085BR, IBM8k & ASR4810SAS were incorrect and would not initialize the adapters correctly. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/linit.c | 72 ++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 33 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 41255f7893d..2bd59426788 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -120,36 +120,39 @@ static struct pci_device_id aac_pci_tbl[] = { { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */ { 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */ { 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */ - { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 32 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 32 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 33 }, /* Callisto Jupiter Platform */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 34 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 35 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 36 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ - { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 37 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ - { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 38 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ - { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 39 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 40 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 41 }, /* AAR-2610SA PCI SATA 6ch */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 42 }, /* ASR-2240S (SabreExpress) */ - { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 43 }, /* ASR-4005SAS */ - { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 44 }, /* IBM 8i (AvonPark) */ - { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 44 }, /* IBM 8i (AvonPark Lite) */ - { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 45 }, /* ASR-4000SAS (BlackBird) */ - { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 46 }, /* ASR-4800SAS (Marauder-X) */ - { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 47 }, /* ASR-4805SAS (Marauder-E) */ - { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 48 }, /* ASR-4810SAS (Hurricane */ - - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 49 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 50 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 51 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 52 }, /* Dell PERC2/QC */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 53 }, /* HP NetRAID-4M */ - - { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 54 }, /* Dell Catchall */ - { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 55 }, /* Legend Catchall */ - { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 56 }, /* Adaptec Catch All */ - { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 57 }, /* Adaptec Rocket Catch All */ + { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */ + { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */ + { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */ + { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ + { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ + { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ + { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ + { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ + { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */ + { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */ + { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */ + { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */ + { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */ + { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */ + { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */ + { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */ + { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */ + + { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/ + { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */ + { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */ + + { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */ + { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */ + { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ + { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -191,8 +194,9 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP5085AU ", 1 }, /* ICP5085AU (Hurricane) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ + { aac_rx_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ + { aac_rx_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ + { aac_rkt_init, "aacraid", "ICP ", "ICP9067MA ", 1 }, /* ICP9067MA (Intruder-6) */ { NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */ { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ @@ -206,10 +210,12 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ { aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ + { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */ + { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ -- cgit v1.2.3 From 0d7323c865608dffb1ed39ec2f3841697ec3e009 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 8 Aug 2005 19:01:43 -0400 Subject: [SCSI] blacklist addition. When run on a kernel that scans all LUNs, a certain crappy scsi scanner reports the same LUN over and over.. https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=155457 Aparently they were so shamed by this, they chose to remain anonymous. Though it seems the blacklist code handles anonymous vendors just fine. Signed-off-by: Dave Jones Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 6121dc1bfad..d9963a848d9 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -114,6 +114,7 @@ static struct { {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ + {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */ /* * Other types of devices that have special flags. -- cgit v1.2.3 From a80b3424d9fde3c4b6d62adaf6dda78128dc5c27 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 8 Aug 2005 19:06:50 -0500 Subject: [SCSI] aic79xx: fix boot panic with no hardware There's a spurious (and illegal since it's marked __exit) call to ahc_linux_exit() in ahc_linux_init() which causes a double list deletion of the transport class; remove it. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 +--- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index acaeebd5046..2f158624c5d 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2326,8 +2326,6 @@ done: return (retval); } -static void ahd_linux_exit(void); - static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2772,7 +2770,7 @@ ahd_linux_init(void) if (ahd_linux_detect(&aic79xx_driver_template) > 0) return 0; spi_release_transport(ahd_linux_transport_template); - ahd_linux_exit(); + return -ENODEV; } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 3fbc10e58cc..22434849de4 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -2335,8 +2335,6 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc) { } -static void ahc_linux_exit(void); - static void ahc_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); -- cgit v1.2.3 From 507caac75e86bd041c5462e5e988fb7138e21d79 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 9 Aug 2005 12:57:11 -0500 Subject: [SCSI] Make the HSG80 a REPORTLUN2 device From: Steve Wilcox In order to properly report LUN's > 7, the DEC HSG80 definition in scsi_devinfo.c needs to include BLIST_REPORTLUN2 rather than BLIST_SPARSELUN. I've tested this change with several HSG firmware revisions and with both Emulex and Qlogic HBA's. Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index d9963a848d9..b444ec2e1c6 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -136,7 +136,7 @@ static struct { {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, - {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ -- cgit v1.2.3 From 483f05f0134e60b724bc3678507c1def860c56d5 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:45 -0400 Subject: [SCSI] lpfc driver 8.0.30 : fix iocb reuse initialization IOCB BDE not getting fully initialized during reuse Symptoms: Driver gets Status 3 and Reason 0x13 on IOCB completions. Cause: The IOCB bpl.bdeSize and bdeFlags are not getting initialized on reuse. Fix: Reinitialize these fields in prep_dma each time an IOCB is used. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 17e4974d444..7cb1e467734 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -238,6 +238,8 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen; if (datadir == DMA_TO_DEVICE) bpl->tus.f.bdeFlags = 0; + else + bpl->tus.f.bdeFlags = BUFF_USE_RCV; bpl->tus.w = le32_to_cpu(bpl->tus.w); num_bde = 1; bpl++; @@ -245,8 +247,11 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) /* * Finish initializing those IOCB fields that are dependent on the - * scsi_cmnd request_buffer + * scsi_cmnd request_buffer. Note that the bdeSize is explicitly + * reinitialized since all iocb memory resources are used many times + * for transmit, receive, and continuation bpl's. */ + iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); iocb_cmd->un.fcpi64.bdl.bdeSize += (num_bde * sizeof (struct ulp_bde64)); iocb_cmd->ulpBdeCount = 1; -- cgit v1.2.3 From 8cbdc5fffa15d5c573e2531c6f533822d08b6b0f Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:50 -0400 Subject: [SCSI] lpfc driver 8.0.30 : fix lip/cablepull panic Fix panic on lip and cable pull Symptoms: Panic on lip or cable pull Cause: Use after free of nlp in lpfc_nlp_remove() Fix: Do not make FC transport calls after a node is removed. Transport calls are disabled by ignoring the initial delete transition. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 233901e9dfd..2e44824a3bd 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1135,6 +1135,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) switch(list) { case NLP_NO_LIST: /* No list, just remove it */ lpfc_nlp_remove(phba, nlp); + /* as node removed - stop further transport calls */ + rport_del = none; break; case NLP_UNUSED_LIST: spin_lock_irq(phba->host->host_lock); -- cgit v1.2.3 From 69859dc47744430ecda16522b0791b6d17e3fa93 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:37 -0400 Subject: [SCSI] lpfc driver 8.0.30 : task mgmt bit clearing Clear task management bits when preparing SCSI commands In lpfc_scsi_prep_cmnd, clear the task management bits (fcpCntl2 member in the fcp_cmd structure) when preparing regular SCSI commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7cb1e467734..15e747faaa5 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -450,6 +450,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, int datadir = scsi_cmnd->sc_data_direction; lpfc_cmd->fcp_rsp->rspSnsLen = 0; + /* clear task management bits */ + lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); -- cgit v1.2.3 From f888ba3ce77c66bece3d804caf7d559838209a4a Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:01 -0400 Subject: [SCSI] lpfc driver 8.0.30 : fix get_stats panic Fix panic in lpfc_get_stats() Symptoms: Panic on sysfs stats access Cause: In lpfc_get_stats() we are writing to memory that we do not own. Fix: Fix our stats structure allocation. Embed phba->link_stats in struct lpfc_hba and stop treating it like rogue structure. Note: Embedding midlayer/transport structure in our structure caused need for more files to include midlayer/transport headers. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 5 ++--- drivers/scsi/lpfc/lpfc_attr.c | 5 +++-- drivers/scsi/lpfc/lpfc_ct.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 4 +--- drivers/scsi/lpfc/lpfc_mbox.c | 3 +++ drivers/scsi/lpfc/lpfc_mem.c | 3 +++ drivers/scsi/lpfc/lpfc_sli.c | 1 + 7 files changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3bb82aae432..adb95674823 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -342,9 +342,6 @@ struct lpfc_hba { #define VPD_MASK 0xf /* mask for any vpd data */ struct timer_list els_tmofunc; - - void *link_stats; - /* * stat counters */ @@ -370,6 +367,8 @@ struct lpfc_hba { struct list_head freebufList; struct list_head ctrspbuflist; struct list_head rnidrspbuflist; + + struct fc_host_statistics link_stats; }; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 3cea9288301..f37b7642c59 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -988,8 +988,7 @@ lpfc_get_stats(struct Scsi_Host *shost) { struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; struct lpfc_sli *psli = &phba->sli; - struct fc_host_statistics *hs = - (struct fc_host_statistics *)phba->link_stats; + struct fc_host_statistics *hs = &phba->link_stats; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc=0; @@ -1020,6 +1019,8 @@ lpfc_get_stats(struct Scsi_Host *shost) return NULL; } + memset(hs, 0, sizeof (struct fc_host_statistics)); + hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256); hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 78adee4699a..b3880eca2f3 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -29,6 +29,7 @@ #include #include +#include #include "lpfc_hw.h" #include "lpfc_sli.h" diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 34d416d2b00..1b6d1dcdabb 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1339,14 +1339,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) if (pci_request_regions(pdev, LPFC_DRIVER_NAME)) goto out_disable_device; - host = scsi_host_alloc(&lpfc_template, - sizeof (struct lpfc_hba) + sizeof (unsigned long)); + host = scsi_host_alloc(&lpfc_template, sizeof (struct lpfc_hba)); if (!host) goto out_release_regions; phba = (struct lpfc_hba*)host->hostdata; memset(phba, 0, sizeof (struct lpfc_hba)); - phba->link_stats = (void *)&phba[1]; phba->host = host; phba->fc_flag |= FC_LOADING; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index c27cf94795d..afcd54d51f1 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -23,6 +23,9 @@ #include #include +#include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index a5cfb6421fa..034a8bfa9ac 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -23,6 +23,9 @@ #include #include +#include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1775508ed27..e027f470810 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "lpfc_hw.h" #include "lpfc_sli.h" -- cgit v1.2.3 From ea84c3f74df646a0897e95c78147190517a751a9 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:30 -0400 Subject: [SCSI] lpfc driver 8.0.30 : dev_loss and nodev timeouts Fix handling of the dev_loss and nodev timeouts. Symptoms: when remote port disappears for a period of time longer then either nodev_tmo or dev_loss_tmo, the lpfc driver worker thread will stall removing that remote port. Cause: removing remote port involves un-blocking and sync-ing corresponding block device queue. But corresponding node in the lpfc driver is still in the NPR(?node port recovery?) state and mid-layer gets SCSI_MLQUEUE_HOST_BUSY as a return value when it is trying to call queuecommand() with command for that node (AKA remote port) Fix: Instead of returning SCSI_MLQUEUE_HOST_BUS from queuecommand() for nodes in NPR states complete it with retry-able error code DID_BUS_BUSY Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 15e747faaa5..4be506a33a2 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -753,6 +753,10 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = ScsiResult(DID_NO_CONNECT, 0); goto out_fail_command; } + else if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + cmnd->result = ScsiResult(DID_BUS_BUSY, 0); + goto out_fail_command; + } /* * The device is most likely recovered and the driver * needs a bit more time to finish. Ask the midlayer -- cgit v1.2.3 From 918865230e55b1fece2d8edec39d46c00626590b Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:09 -0400 Subject: [SCSI] lpfc driver 8.0.30 : convert to use of int_to_scsilun() Replace use of lpfc_put_lun with midlayer's int_to_scsilun Remove driver's local definition of lpfc_put_lun (which converts an int back to a 64-bit LUN) and replace it's use with the recently added int_to_scsilun function provided by the midlayer. Note: Embedding midlayer structure in our structure caused need for more files to include midlayer headers. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 1 + drivers/scsi/lpfc/lpfc_ct.c | 1 + drivers/scsi/lpfc/lpfc_els.c | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 2 ++ drivers/scsi/lpfc/lpfc_mem.c | 2 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 1 + drivers/scsi/lpfc/lpfc_scsi.c | 11 ++++------- drivers/scsi/lpfc/lpfc_scsi.h | 13 +------------ drivers/scsi/lpfc/lpfc_sli.c | 1 + 11 files changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f37b7642c59..0e089a42c03 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index b3880eca2f3..1280f0e5463 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2b1c9572dae..63caf7fe972 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2e44824a3bd..0a8269d6b13 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1b6d1dcdabb..6f3cb59bf9e 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index afcd54d51f1..73eb89f9159 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -26,6 +26,8 @@ #include #include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 034a8bfa9ac..0aba13ceaac 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -26,6 +26,8 @@ #include #include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 45dc0210fc4..9b35eaac781 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 4be506a33a2..b5ad1871d34 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -40,11 +40,6 @@ #define LPFC_RESET_WAIT 2 #define LPFC_ABORT_WAIT 2 -static inline void lpfc_put_lun(struct fcp_cmnd *fcmd, unsigned int lun) -{ - fcmd->fcpLunLsl = 0; - fcmd->fcpLunMsl = swab16((uint16_t)lun); -} /* * This routine allocates a scsi buffer, which contains all the necessary @@ -453,7 +448,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, /* clear task management bits */ lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; - lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); @@ -552,7 +548,8 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, piocb = &piocbq->iocb; fcp_cmnd = lpfc_cmd->fcp_cmnd; - lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); fcp_cmnd->fcpCntl2 = task_mgmt_cmd; piocb->ulpCommand = CMD_FCP_ICMND64_CR; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 0fd9ba14e1b..acd64c49e84 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -78,18 +78,7 @@ struct fcp_rsp { }; struct fcp_cmnd { - uint32_t fcpLunMsl; /* most significant lun word (32 bits) */ - uint32_t fcpLunLsl; /* least significant lun word (32 bits) */ - /* # of bits to shift lun id to end up in right - * payload word, little endian = 8, big = 16. - */ -#ifdef __BIG_ENDIAN -#define FC_LUN_SHIFT 16 -#define FC_ADDR_MODE_SHIFT 24 -#else /* __LITTLE_ENDIAN */ -#define FC_LUN_SHIFT 8 -#define FC_ADDR_MODE_SHIFT 0 -#endif + struct scsi_lun fcp_lun; uint8_t fcpCntl0; /* FCP_CNTL byte 0 (reserved) */ uint8_t fcpCntl1; /* FCP_CNTL byte 1 task codes */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e027f470810..e74e224fd77 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 9909b79e3d533b422c6c72945da35aef124dbce1 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:17 -0400 Subject: [SCSI] lpfc driver 8.0.30 : update version to 8.0.30 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 47dea48ee0e..7e6747b06f9 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.0.29" +#define LPFC_DRIVER_VERSION "8.0.30" #define LPFC_DRIVER_NAME "lpfc" -- cgit v1.2.3 From 6becdff3bcaff1b89c392cf0630dcb5759704492 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Tue, 9 Aug 2005 00:17:03 -0700 Subject: [SCSI] fix warning in scsi_softirq From: Andrew Morton drivers/scsi/scsi.c: In function `scsi_softirq': drivers/scsi/scsi.c:814: warning: int format, long int arg (arg 4) Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 4befbc275f9..a780546eda9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -811,7 +811,7 @@ static void scsi_softirq(struct softirq_action *h) if (disposition != SUCCESS && time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { dev_printk(KERN_ERR, &cmd->device->sdev_gendev, - "timing out command, waited %ds\n", + "timing out command, waited %lus\n", wait_for/HZ); disposition = SUCCESS; } -- cgit v1.2.3 From 0336ee5aed1f9a5a6a04e3deabd7797dc193ccd3 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 8 Aug 2005 21:49:48 -0700 Subject: [SCSI] fix warning in aic7770.c From: "Martin J. Bligh" drivers/scsi/aic7xxx/aic7770.c: In function `aic7770_config': drivers/scsi/aic7xxx/aic7770.c:129: warning: unused variable `l' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7770.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 00f3bd1e181..527efd36f5c 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -126,7 +126,6 @@ aic7770_find_device(uint32_t id) int aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) { - u_long l; int error; int have_seeprom; u_int hostconf; -- cgit v1.2.3 From 3a4f5c60dbe1978580ea03c1aff353d1e63d1638 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 13 Aug 2005 09:42:45 -0500 Subject: [SCSI] aic7xxx: lost multifunction flags handling From: Christoph Hellwig Multi-function cards need to inherit the PCI flags from the master PCI device. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 9d318ce2c99..0d44a6907dd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -149,6 +149,27 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev) ahc_free(ahc); } +static void +ahc_linux_pci_inherit_flags(struct ahc_softc *ahc) +{ + struct pci_dev *pdev = ahc->dev_softc, *master_pdev; + unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + + master_pdev = pci_get_slot(pdev->bus, master_devfn); + if (master_pdev) { + struct ahc_softc *master = pci_get_drvdata(master_pdev); + if (master) { + ahc->flags &= ~AHC_BIOS_ENABLED; + ahc->flags |= master->flags & AHC_BIOS_ENABLED; + + ahc->flags &= ~AHC_PRIMARY_CHANNEL; + ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL; + } else + printk(KERN_ERR "aic7xxx: no multichannel peer found!\n"); + pci_dev_put(master_pdev); + } +} + static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -203,6 +224,14 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_free(ahc); return (-error); } + + /* + * Second Function PCI devices need to inherit some + * settings from function 0. + */ + if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) + ahc_linux_pci_inherit_flags(ahc); + pci_set_drvdata(pdev, ahc); ahc_linux_register_host(ahc, &aic7xxx_driver_template); return (0); -- cgit v1.2.3 From 10c1b88987d618f4f89c10e11e574c76de73b5e7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 14 Aug 2005 14:34:06 -0500 Subject: [SCSI] add ability to deny binding to SPI transport class This patch is necessary if we begin exposing underlying physical disks (which can attach to the SPI transport class) of the hardware RAID cards, since we don't want any SPI parameters binding to the RAID devices. Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index e7b9570c818..02134fce217 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1082,6 +1082,7 @@ static int spi_device_match(struct attribute_container *cont, { struct scsi_device *sdev; struct Scsi_Host *shost; + struct spi_internal *i; if (!scsi_is_sdev_device(dev)) return 0; @@ -1094,6 +1095,9 @@ static int spi_device_match(struct attribute_container *cont, /* Note: this class has no device attributes, so it has * no per-HBA allocation and thus we don't need to distinguish * the attribute containers for the device */ + i = to_spi_internal(shost->transportt); + if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target)) + return 0; return 1; } @@ -1101,6 +1105,7 @@ static int spi_target_match(struct attribute_container *cont, struct device *dev) { struct Scsi_Host *shost; + struct scsi_target *starget; struct spi_internal *i; if (!scsi_is_target_device(dev)) @@ -1112,7 +1117,11 @@ static int spi_target_match(struct attribute_container *cont, return 0; i = to_spi_internal(shost->transportt); - + starget = to_scsi_target(dev); + + if (i->f->deny_binding && i->f->deny_binding(starget)) + return 0; + return &i->t.target_attrs.ac == cont; } -- cgit v1.2.3 From d0a7e574007fd547d72ec693bfa35778623d0738 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 14 Aug 2005 17:09:01 -0500 Subject: [SCSI] correct transport class abstraction to work outside SCSI I recently tried to construct a totally generic transport class and found there were certain features missing from the current abstract transport class. Most notable is that you have to hang the data on the class_device but most of the API is framed in terms of the generic device, not the class_device. These changes are two fold - Provide the class_device to all of the setup and configure APIs - Provide and extra API to take the device and the attribute class and return the corresponding class_device Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_fc.c | 6 ++++-- drivers/scsi/scsi_transport_spi.c | 11 ++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 35d1c1e8e34..96243c7fe11 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -252,7 +252,8 @@ struct fc_internal { #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) -static int fc_target_setup(struct device *dev) +static int fc_target_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct scsi_target *starget = to_scsi_target(dev); struct fc_rport *rport = starget_to_rport(starget); @@ -281,7 +282,8 @@ static DECLARE_TRANSPORT_CLASS(fc_transport_class, NULL, NULL); -static int fc_host_setup(struct device *dev) +static int fc_host_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 02134fce217..89f6b7feb9c 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -162,7 +162,8 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name) return SPI_SIGNAL_UNKNOWN; } -static int spi_host_setup(struct device *dev) +static int spi_host_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); @@ -196,7 +197,9 @@ static int spi_host_match(struct attribute_container *cont, return &i->t.host_attrs.ac == cont; } -static int spi_device_configure(struct device *dev) +static int spi_device_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) { struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; @@ -214,7 +217,9 @@ static int spi_device_configure(struct device *dev) return 0; } -static int spi_setup_transport_attrs(struct device *dev) +static int spi_setup_transport_attrs(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) { struct scsi_target *starget = to_scsi_target(dev); -- cgit v1.2.3 From d46b1d549e1414d673e0ec18219f4f5e30d5f3f5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:27:39 +0200 Subject: [SCSI] aic79xx: remove some dead code remove some dead cruft, as done already in aic7xxx Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.h | 35 ---------------------------------- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 3 --- 2 files changed, 38 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 46edcf3e4e6..296d3a59efe 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -254,39 +254,8 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#define AHD_SCSI_HAS_HOST_LOCK 1 - #define AIC79XX_DRIVER_VERSION "1.3.11" -/**************************** Front End Queues ********************************/ -/* - * Data structure used to cast the Linux struct scsi_cmnd to something - * that allows us to use the queue macros. The linux structure has - * plenty of space to hold the links fields as required by the queue - * macros, but the queue macors require them to have the correct type. - */ -struct ahd_cmd_internal { - /* Area owned by the Linux scsi layer. */ - uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; - union { - STAILQ_ENTRY(ahd_cmd) ste; - LIST_ENTRY(ahd_cmd) le; - TAILQ_ENTRY(ahd_cmd) tqe; - } links; - uint32_t end; -}; - -struct ahd_cmd { - union { - struct ahd_cmd_internal icmd; - struct scsi_cmnd scsi_cmd; - } un; -}; - -#define acmd_icmd(cmd) ((cmd)->un.icmd) -#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) -#define acmd_links un.icmd.links - /*************************** Device Data Structures ***************************/ /* * A per probed device structure used to deal with some error recovery @@ -297,13 +266,10 @@ struct ahd_cmd { */ typedef enum { - AHD_DEV_UNCONFIGURED = 0x01, AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ - AHD_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ } ahd_linux_dev_flags; struct ahd_linux_target; @@ -432,7 +398,6 @@ struct ahd_platform_data { uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - uint64_t hw_dma_mask; #define AHD_SCB_UP_EH_SEM 0x1 uint32_t flags; }; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 91daf0c7fb1..7cfb2eb2b86 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -177,15 +177,12 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (memsize >= 0x8000000000ULL && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK; } else if (memsize > 0x80000000 && pci_set_dma_mask(pdev, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = mask_39bit; } } else { pci_set_dma_mask(pdev, DMA_32BIT_MASK); - ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK; } ahd->dev_softc = pci; error = ahd_pci_config(ahd, entry); -- cgit v1.2.3 From 85a46523ff68aa0e4d2477c51075ffd9fc7e7a14 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:28:46 +0200 Subject: [SCSI] aic79xx: sane pci probing remove ahd_tailq and do sane pci probing. ported over from aic7xxx. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx.h | 6 -- drivers/scsi/aic7xxx/aic79xx_core.c | 103 +------------------------------ drivers/scsi/aic7xxx/aic79xx_osm.c | 108 ++++++--------------------------- drivers/scsi/aic7xxx/aic79xx_osm.h | 30 --------- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 79 +++++++++++------------- drivers/scsi/aic7xxx/aic79xx_pci.c | 14 +---- drivers/scsi/aic7xxx/aic79xx_proc.c | 11 +--- 7 files changed, 60 insertions(+), 291 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index fd4b2f3eb0c..653fb0b42ae 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1247,9 +1247,6 @@ struct ahd_softc { uint16_t user_tagenable;/* Tagged Queuing allowed */ }; -TAILQ_HEAD(ahd_softc_tailq, ahd_softc); -extern struct ahd_softc_tailq ahd_tailq; - /*************************** IO Cell Configuration ****************************/ #define AHD_PRECOMP_SLEW_INDEX \ (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0) @@ -1374,8 +1371,6 @@ void ahd_enable_coalescing(struct ahd_softc *ahd, void ahd_pause_and_flushwork(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd); int ahd_resume(struct ahd_softc *ahd); -void ahd_softc_insert(struct ahd_softc *); -struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd); void ahd_set_unit(struct ahd_softc *, int); void ahd_set_name(struct ahd_softc *, char *); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); @@ -1524,7 +1519,6 @@ void ahd_print_scb(struct scb *scb); void ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); void ahd_dump_sglist(struct scb *scb); -void ahd_dump_all_cards_state(void); void ahd_dump_card_state(struct ahd_softc *ahd); int ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index d69bbffb34a..4e8f00df978 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -52,8 +52,6 @@ #include #endif -/******************************** Globals *************************************/ -struct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq); /***************************** Lookup Tables **********************************/ char *ahd_chip_names[] = @@ -5179,74 +5177,6 @@ ahd_softc_init(struct ahd_softc *ahd) return (0); } -void -ahd_softc_insert(struct ahd_softc *ahd) -{ - struct ahd_softc *list_ahd; - -#if AHD_PCI_CONFIG > 0 - /* - * Second Function PCI devices need to inherit some - * settings from function 0. - */ - if ((ahd->features & AHD_MULTI_FUNC) != 0) { - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - ahd_dev_softc_t list_pci; - ahd_dev_softc_t pci; - - list_pci = list_ahd->dev_softc; - pci = ahd->dev_softc; - if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci) - && ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) { - struct ahd_softc *master; - struct ahd_softc *slave; - - if (ahd_get_pci_function(list_pci) == 0) { - master = list_ahd; - slave = ahd; - } else { - master = ahd; - slave = list_ahd; - } - slave->flags &= ~AHD_BIOS_ENABLED; - slave->flags |= - master->flags & AHD_BIOS_ENABLED; - break; - } - } - } -#endif - - /* - * Insertion sort into our list of softcs. - */ - list_ahd = TAILQ_FIRST(&ahd_tailq); - while (list_ahd != NULL - && ahd_softc_comp(ahd, list_ahd) <= 0) - list_ahd = TAILQ_NEXT(list_ahd, links); - if (list_ahd != NULL) - TAILQ_INSERT_BEFORE(list_ahd, ahd, links); - else - TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links); - ahd->init_level++; -} - -/* - * Verify that the passed in softc pointer is for a - * controller that is still configured. - */ -struct ahd_softc * -ahd_find_softc(struct ahd_softc *ahd) -{ - struct ahd_softc *list_ahd; - - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - if (list_ahd == ahd) - return (ahd); - } - return (NULL); -} - void ahd_set_unit(struct ahd_softc *ahd, int unit) { @@ -7902,18 +7832,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) static void ahd_reset_poll(void *arg) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = arg; u_int scsiseq1; - u_long l; u_long s; - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)arg); - if (ahd == NULL) { - printf("ahd_reset_poll: Instance %p no longer exists\n", arg); - ahd_list_unlock(&l); - return; - } ahd_lock(ahd, &s); ahd_pause(ahd); ahd_update_modes(ahd); @@ -7924,7 +7846,6 @@ ahd_reset_poll(void *arg) ahd_reset_poll, ahd); ahd_unpause(ahd); ahd_unlock(ahd, &s); - ahd_list_unlock(&l); return; } @@ -7936,25 +7857,16 @@ ahd_reset_poll(void *arg) ahd->flags &= ~AHD_RESET_POLL_ACTIVE; ahd_unlock(ahd, &s); ahd_release_simq(ahd); - ahd_list_unlock(&l); } /**************************** Statistics Processing ***************************/ static void ahd_stat_timer(void *arg) { - struct ahd_softc *ahd; - u_long l; + struct ahd_softc *ahd = arg; u_long s; int enint_coal; - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)arg); - if (ahd == NULL) { - printf("ahd_stat_timer: Instance %p no longer exists\n", arg); - ahd_list_unlock(&l); - return; - } ahd_lock(ahd, &s); enint_coal = ahd->hs_mailbox & ENINT_COALESCE; @@ -7981,7 +7893,6 @@ ahd_stat_timer(void *arg) ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, ahd_stat_timer, ahd); ahd_unlock(ahd, &s); - ahd_list_unlock(&l); } /****************************** Status Processing *****************************/ @@ -8745,16 +8656,6 @@ sized: return (last_probe); } -void -ahd_dump_all_cards_state(void) -{ - struct ahd_softc *list_ahd; - - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - ahd_dump_card_state(list_ahd); - } -} - int ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, const char *name, u_int address, u_int value, diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2f158624c5d..3feb739cd55 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -59,11 +59,6 @@ static struct scsi_transport_template *ahd_linux_transport_template = NULL; #include /* For block_size() */ #include /* For ssleep/msleep */ -/* - * Lock protecting manipulation of the ahd softc list. - */ -spinlock_t ahd_list_spinlock; - /* * Bucket size for counting good commands in between bad ones. */ @@ -302,13 +297,6 @@ static uint32_t aic79xx_pci_parity = ~0; */ uint32_t aic79xx_allow_memio = ~0; -/* - * aic79xx_detect() has been run, so register all device arrivals - * immediately with the system rather than deferring to the sorted - * attachment performed by aic79xx_detect(). - */ -int aic79xx_detect_complete; - /* * So that we can set how long each device is given as a selection timeout. * The table of values goes like this: @@ -387,7 +375,9 @@ static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; static aic_option_callback_t ahd_linux_setup_iocell_info; static int aic79xx_setup(char *c); -static int ahd_linux_next_unit(void); + +static int ahd_linux_unit; + /****************************** Inlines ***************************************/ static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); @@ -417,50 +407,6 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) #define BUILD_SCSIID(ahd, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id) -/* - * Try to detect an Adaptec 79XX controller. - */ -static int -ahd_linux_detect(struct scsi_host_template *template) -{ - struct ahd_softc *ahd; - int found; - int error = 0; - - /* - * If we've been passed any parameters, process them now. - */ - if (aic79xx) - aic79xx_setup(aic79xx); - - template->proc_name = "aic79xx"; - - /* - * Initialize our softc list lock prior to - * probing for any adapters. - */ - ahd_list_lockinit(); - -#ifdef CONFIG_PCI - error = ahd_linux_pci_init(); - if (error) - return error; -#endif - - /* - * Register with the SCSI layer all - * controllers we've found. - */ - found = 0; - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - - if (ahd_linux_register_host(ahd, template) == 0) - found++; - } - aic79xx_detect_complete++; - return found; -} - /* * Return a string describing the driver. */ @@ -760,6 +706,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) struct scsi_host_template aic79xx_driver_template = { .module = THIS_MODULE, .name = "aic79xx", + .proc_name = "aic79xx", .proc_info = ahd_linux_proc_info, .info = ahd_linux_info, .queuecommand = ahd_linux_queue, @@ -1072,7 +1019,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa host->max_lun = AHD_NUM_LUNS; host->max_channel = 0; host->sg_tablesize = AHD_NSEG; - ahd_set_unit(ahd, ahd_linux_next_unit()); + ahd_set_unit(ahd, ahd_linux_unit++); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1100,29 +1047,6 @@ ahd_linux_get_memsize(void) return ((uint64_t)si.totalram << PAGE_SHIFT); } -/* - * Find the smallest available unit number to use - * for a new device. We don't just use a static - * count to handle the "repeated hot-(un)plug" - * scenario. - */ -static int -ahd_linux_next_unit(void) -{ - struct ahd_softc *ahd; - int unit; - - unit = 0; -retry: - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->unit == unit) { - unit++; - goto retry; - } - } - return (unit); -} - /* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any @@ -2755,23 +2679,31 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_hold_mcs = 1, }; - - static int __init ahd_linux_init(void) { - ahd_linux_transport_template = spi_attach_transport(&ahd_linux_transport_functions); + int error = 0; + + /* + * If we've been passed any parameters, process them now. + */ + if (aic79xx) + aic79xx_setup(aic79xx); + + ahd_linux_transport_template = + spi_attach_transport(&ahd_linux_transport_functions); 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)); - if (ahd_linux_detect(&aic79xx_driver_template) > 0) - return 0; - spi_release_transport(ahd_linux_transport_template); - return -ENODEV; + error = ahd_linux_pci_init(); + if (error) + spi_release_transport(ahd_linux_transport_template); + return error; } static void __exit diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 296d3a59efe..052c6619acc 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -120,7 +120,6 @@ typedef struct scsi_cmnd *ahd_io_ctx_t; /************************* Configuration Data *********************************/ extern uint32_t aic79xx_allow_memio; -extern int aic79xx_detect_complete; extern struct scsi_host_template aic79xx_driver_template; /***************************** Bus Space/DMA **********************************/ @@ -532,17 +531,6 @@ void ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo); /******************************** Locking *************************************/ -/* Lock protecting internal data structures */ -static __inline void ahd_lockinit(struct ahd_softc *); -static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags); -static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags); - -/* Lock held during ahd_list manipulation and ahd softc frees */ -extern spinlock_t ahd_list_spinlock; -static __inline void ahd_list_lockinit(void); -static __inline void ahd_list_lock(unsigned long *flags); -static __inline void ahd_list_unlock(unsigned long *flags); - static __inline void ahd_lockinit(struct ahd_softc *ahd) { @@ -561,24 +549,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); } -static __inline void -ahd_list_lockinit(void) -{ - spin_lock_init(&ahd_list_spinlock); -} - -static __inline void -ahd_list_lock(unsigned long *flags) -{ - spin_lock_irqsave(&ahd_list_spinlock, *flags); -} - -static __inline void -ahd_list_unlock(unsigned long *flags) -{ - spin_unlock_irqrestore(&ahd_list_spinlock, *flags); -} - /******************************* PCI Definitions ******************************/ /* * PCIM_xxx: mask to locate subfield in register diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 7cfb2eb2b86..390b53852d4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -92,27 +92,31 @@ struct pci_driver aic79xx_pci_driver = { static void ahd_linux_pci_dev_remove(struct pci_dev *pdev) { - struct ahd_softc *ahd; - u_long l; + struct ahd_softc *ahd = pci_get_drvdata(pdev); + u_long s; - /* - * We should be able to just perform - * the free directly, but check our - * list for extra sanity. - */ - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev)); - if (ahd != NULL) { - u_long s; - - TAILQ_REMOVE(&ahd_tailq, ahd, links); - ahd_list_unlock(&l); - ahd_lock(ahd, &s); - ahd_intr_enable(ahd, FALSE); - ahd_unlock(ahd, &s); - ahd_free(ahd); - } else - ahd_list_unlock(&l); + ahd_lock(ahd, &s); + ahd_intr_enable(ahd, FALSE); + ahd_unlock(ahd, &s); + ahd_free(ahd); +} + +static void +ahd_linux_pci_inherit_flags(struct ahd_softc *ahd) +{ + struct pci_dev *pdev = ahd->dev_softc, *master_pdev; + unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + + master_pdev = pci_get_slot(pdev->bus, master_devfn); + if (master_pdev) { + struct ahd_softc *master = pci_get_drvdata(master_pdev); + if (master) { + ahd->flags &= ~AHD_BIOS_ENABLED; + ahd->flags |= master->flags & AHD_BIOS_ENABLED; + } else + printk(KERN_ERR "aic79xx: no multichannel peer found!\n"); + pci_dev_put(master_pdev); + } } static int @@ -125,22 +129,6 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) char *name; int error; - /* - * Some BIOSen report the same device multiple times. - */ - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - struct pci_dev *probed_pdev; - - probed_pdev = ahd->dev_softc; - if (probed_pdev->bus->number == pdev->bus->number - && probed_pdev->devfn == pdev->devfn) - break; - } - if (ahd != NULL) { - /* Skip duplicate. */ - return (-ENODEV); - } - pci = pdev; entry = ahd_find_pci_device(pci); if (entry == NULL) @@ -190,16 +178,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahd_free(ahd); return (-error); } + + /* + * Second Function PCI devices need to inherit some + * * settings from function 0. + */ + if ((ahd->features & AHD_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) + ahd_linux_pci_inherit_flags(ahd); + pci_set_drvdata(pdev, ahd); - if (aic79xx_detect_complete) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - ahd_linux_register_host(ahd, &aic79xx_driver_template); -#else - printf("aic79xx: ignoring PCI device found after " - "initialization\n"); - return (-ENODEV); -#endif - } + + ahd_linux_register_host(ahd, &aic79xx_driver_template); return (0); } diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 703f6e44889..2131db60018 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -283,7 +283,6 @@ int ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) { struct scb_data *shared_scb_data; - u_long l; u_int command; uint32_t devconfig; uint16_t subvendor; @@ -373,16 +372,9 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) * Allow interrupts now that we are completely setup. */ error = ahd_pci_map_int(ahd); - if (error != 0) - return (error); - - ahd_list_lock(&l); - /* - * Link this softc in with all other ahd instances. - */ - ahd_softc_insert(ahd); - ahd_list_unlock(&l); - return (0); + if (!error) + ahd->init_level++; + return error; } /* diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index cffdd104f9e..32be1f55998 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -285,21 +285,13 @@ int ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata; struct info_str info; char ahd_info[256]; - u_long l; u_int max_targ; u_int i; int retval; - retval = -EINVAL; - ahd_list_lock(&l); - ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); - - if (ahd == NULL) - goto done; - /* Has data been written to the file? */ if (inout == TRUE) { retval = ahd_proc_write_seeprom(ahd, buffer, length); @@ -349,6 +341,5 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, } retval = info.pos > info.offset ? info.pos - info.offset : 0; done: - ahd_list_unlock(&l); return (retval); } -- cgit v1.2.3 From 975f24bdc7d3833875309509abbc7da2b2a28234 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:29:55 +0200 Subject: [SCSI] aiclib remove dead remove lots of completely dead code from aiclib, there's not a lot left and even what's left is rather useless. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aiclib.c | 1256 ----------------------------------------- drivers/scsi/aic7xxx/aiclib.h | 868 ---------------------------- 2 files changed, 2124 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 7c5a6db0e67..4d44a921118 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -30,1162 +30,8 @@ * $Id$ */ -#include -#include -#include - -/* Core SCSI definitions */ -#include #include "aiclib.h" -#include "cam.h" - -#ifndef FALSE -#define FALSE 0 -#endif /* FALSE */ -#ifndef TRUE -#define TRUE 1 -#endif /* TRUE */ -#ifndef ERESTART -#define ERESTART -1 /* restart syscall */ -#endif -#ifndef EJUSTRETURN -#define EJUSTRETURN -2 /* don't modify regs, just return */ -#endif - -static int ascentrycomp(const void *key, const void *member); -static int senseentrycomp(const void *key, const void *member); -static void fetchtableentries(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *, - const struct sense_key_table_entry **, - const struct asc_table_entry **); -static void * scsibsearch(const void *key, const void *base, size_t nmemb, - size_t size, - int (*compar)(const void *, const void *)); -typedef int (cam_quirkmatch_t)(caddr_t, caddr_t); -static int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, - int str_len); -static caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, - int num_entries, int entry_size, - cam_quirkmatch_t *comp_func); - -#define SCSI_NO_SENSE_STRINGS 1 -#if !defined(SCSI_NO_SENSE_STRINGS) -#define SST(asc, ascq, action, desc) \ - asc, ascq, action, desc -#else -static const char empty_string[] = ""; - -#define SST(asc, ascq, action, desc) \ - asc, ascq, action, empty_string -#endif - -static const struct sense_key_table_entry sense_key_table[] = -{ - { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, - { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, - { - SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, - "NOT READY" - }, - { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, - { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, - { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, - { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, - { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" }, - { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" }, - { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, - { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, - { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, - { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, - { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, - { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, - { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" } -}; - -static const int sense_key_table_size = - sizeof(sense_key_table)/sizeof(sense_key_table[0]); - -static struct asc_table_entry quantum_fireball_entries[] = { - {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, initializing cmd. required")} -}; - -static struct asc_table_entry sony_mo_entries[] = { - {SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, cause not reportable")} -}; - -static struct scsi_sense_quirk_entry sense_quirk_table[] = { - { - /* - * The Quantum Fireball ST and SE like to return 0x04 0x0b when - * they really should return 0x04 0x02. 0x04,0x0b isn't - * defined in any SCSI spec, and it isn't mentioned in the - * hardware manual for these drives. - */ - {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, - /*num_sense_keys*/0, - sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), - /*sense key entries*/NULL, - quantum_fireball_entries - }, - { - /* - * This Sony MO drive likes to return 0x04, 0x00 when it - * isn't spun up. - */ - {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"}, - /*num_sense_keys*/0, - sizeof(sony_mo_entries)/sizeof(struct asc_table_entry), - /*sense key entries*/NULL, - sony_mo_entries - } -}; - -static const int sense_quirk_table_size = - sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); - -static struct asc_table_entry asc_table[] = { -/* - * From File: ASC-NUM.TXT - * SCSI ASC/ASCQ Assignments - * Numeric Sorted Listing - * as of 5/12/97 - * - * D - DIRECT ACCESS DEVICE (SBC) device column key - * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- - * . L - PRINTER DEVICE (SSC) blank = reserved - * . P - PROCESSOR DEVICE (SPC) not blank = allowed - * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) - * . . R - CD DEVICE (MMC) - * . . S - SCANNER DEVICE (SGC) - * . . .O - OPTICAL MEMORY DEVICE (SBC) - * . . . M - MEDIA CHANGER DEVICE (SMC) - * . . . C - COMMUNICATION DEVICE (SSC) - * . . . .A - STORAGE ARRAY DEVICE (SCC) - * . . . . E - ENCLOSURE SERVICES DEVICE (SES) - * DTLPWRSOMCAE ASC ASCQ Action Description - * ------------ ---- ---- ------ -----------------------------------*/ -/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP, - "No additional sense information") }, -/* T S */{SST(0x00, 0x01, SS_RDEF, - "Filemark detected") }, -/* T S */{SST(0x00, 0x02, SS_RDEF, - "End-of-partition/medium detected") }, -/* T */{SST(0x00, 0x03, SS_RDEF, - "Setmark detected") }, -/* T S */{SST(0x00, 0x04, SS_RDEF, - "Beginning-of-partition/medium detected") }, -/* T S */{SST(0x00, 0x05, SS_RDEF, - "End-of-data detected") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF, - "I/O process terminated") }, -/* R */{SST(0x00, 0x11, SS_FATAL|EBUSY, - "Audio play operation in progress") }, -/* R */{SST(0x00, 0x12, SS_NOP, - "Audio play operation paused") }, -/* R */{SST(0x00, 0x13, SS_NOP, - "Audio play operation successfully completed") }, -/* R */{SST(0x00, 0x14, SS_RDEF, - "Audio play operation stopped due to error") }, -/* R */{SST(0x00, 0x15, SS_NOP, - "No current audio status to return") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY, - "Operation in progress") }, -/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF, - "Cleaning requested") }, -/* D W O */{SST(0x01, 0x00, SS_RDEF, - "No index/sector signal") }, -/* D WR OM */{SST(0x02, 0x00, SS_RDEF, - "No seek complete") }, -/* DTL W SO */{SST(0x03, 0x00, SS_RDEF, - "Peripheral device write fault") }, -/* T */{SST(0x03, 0x01, SS_RDEF, - "No write current") }, -/* T */{SST(0x03, 0x02, SS_RDEF, - "Excessive write errors") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x00, - SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO, - "Logical unit not ready, cause not reportable") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x01, - SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, - "Logical unit is in process of becoming ready") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, initializing cmd. required") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO, - "Logical unit not ready, manual intervention required")}, -/* DTL O */{SST(0x04, 0x04, SS_FATAL|EBUSY, - "Logical unit not ready, format in progress") }, -/* DT W OMCA */{SST(0x04, 0x05, SS_FATAL|EBUSY, - "Logical unit not ready, rebuild in progress") }, -/* DT W OMCA */{SST(0x04, 0x06, SS_FATAL|EBUSY, - "Logical unit not ready, recalculation in progress") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY, - "Logical unit not ready, operation in progress") }, -/* R */{SST(0x04, 0x08, SS_FATAL|EBUSY, - "Logical unit not ready, long write in progress") }, -/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF, - "Logical unit does not respond to selection") }, -/* D WR OM */{SST(0x06, 0x00, SS_RDEF, - "No reference position found") }, -/* DTL WRSOM */{SST(0x07, 0x00, SS_RDEF, - "Multiple peripheral devices selected") }, -/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF, - "Logical unit communication failure") }, -/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF, - "Logical unit communication time-out") }, -/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF, - "Logical unit communication parity error") }, -/* DT R OM */{SST(0x08, 0x03, SS_RDEF, - "Logical unit communication crc error (ultra-dma/32)")}, -/* DT WR O */{SST(0x09, 0x00, SS_RDEF, - "Track following error") }, -/* WR O */{SST(0x09, 0x01, SS_RDEF, - "Tracking servo failure") }, -/* WR O */{SST(0x09, 0x02, SS_RDEF, - "Focus servo failure") }, -/* WR O */{SST(0x09, 0x03, SS_RDEF, - "Spindle servo failure") }, -/* DT WR O */{SST(0x09, 0x04, SS_RDEF, - "Head select fault") }, -/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC, - "Error log overflow") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF, - "Warning") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF, - "Specified temperature exceeded") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF, - "Enclosure degraded") }, -/* T RS */{SST(0x0C, 0x00, SS_RDEF, - "Write error") }, -/* D W O */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Write error - recovered with auto reallocation") }, -/* D W O */{SST(0x0C, 0x02, SS_RDEF, - "Write error - auto reallocation failed") }, -/* D W O */{SST(0x0C, 0x03, SS_RDEF, - "Write error - recommend reassignment") }, -/* DT W O */{SST(0x0C, 0x04, SS_RDEF, - "Compression check miscompare error") }, -/* DT W O */{SST(0x0C, 0x05, SS_RDEF, - "Data expansion occurred during compression") }, -/* DT W O */{SST(0x0C, 0x06, SS_RDEF, - "Block not compressible") }, -/* R */{SST(0x0C, 0x07, SS_RDEF, - "Write error - recovery needed") }, -/* R */{SST(0x0C, 0x08, SS_RDEF, - "Write error - recovery failed") }, -/* R */{SST(0x0C, 0x09, SS_RDEF, - "Write error - loss of streaming") }, -/* R */{SST(0x0C, 0x0A, SS_RDEF, - "Write error - padding blocks added") }, -/* D W O */{SST(0x10, 0x00, SS_RDEF, - "ID CRC or ECC error") }, -/* DT WRSO */{SST(0x11, 0x00, SS_RDEF, - "Unrecovered read error") }, -/* DT W SO */{SST(0x11, 0x01, SS_RDEF, - "Read retries exhausted") }, -/* DT W SO */{SST(0x11, 0x02, SS_RDEF, - "Error too long to correct") }, -/* DT W SO */{SST(0x11, 0x03, SS_RDEF, - "Multiple read errors") }, -/* D W O */{SST(0x11, 0x04, SS_RDEF, - "Unrecovered read error - auto reallocate failed") }, -/* WR O */{SST(0x11, 0x05, SS_RDEF, - "L-EC uncorrectable error") }, -/* WR O */{SST(0x11, 0x06, SS_RDEF, - "CIRC unrecovered error") }, -/* W O */{SST(0x11, 0x07, SS_RDEF, - "Data re-synchronization error") }, -/* T */{SST(0x11, 0x08, SS_RDEF, - "Incomplete block read") }, -/* T */{SST(0x11, 0x09, SS_RDEF, - "No gap found") }, -/* DT O */{SST(0x11, 0x0A, SS_RDEF, - "Miscorrected error") }, -/* D W O */{SST(0x11, 0x0B, SS_RDEF, - "Unrecovered read error - recommend reassignment") }, -/* D W O */{SST(0x11, 0x0C, SS_RDEF, - "Unrecovered read error - recommend rewrite the data")}, -/* DT WR O */{SST(0x11, 0x0D, SS_RDEF, - "De-compression CRC error") }, -/* DT WR O */{SST(0x11, 0x0E, SS_RDEF, - "Cannot decompress using declared algorithm") }, -/* R */{SST(0x11, 0x0F, SS_RDEF, - "Error reading UPC/EAN number") }, -/* R */{SST(0x11, 0x10, SS_RDEF, - "Error reading ISRC number") }, -/* R */{SST(0x11, 0x11, SS_RDEF, - "Read error - loss of streaming") }, -/* D W O */{SST(0x12, 0x00, SS_RDEF, - "Address mark not found for id field") }, -/* D W O */{SST(0x13, 0x00, SS_RDEF, - "Address mark not found for data field") }, -/* DTL WRSO */{SST(0x14, 0x00, SS_RDEF, - "Recorded entity not found") }, -/* DT WR O */{SST(0x14, 0x01, SS_RDEF, - "Record not found") }, -/* T */{SST(0x14, 0x02, SS_RDEF, - "Filemark or setmark not found") }, -/* T */{SST(0x14, 0x03, SS_RDEF, - "End-of-data not found") }, -/* T */{SST(0x14, 0x04, SS_RDEF, - "Block sequence error") }, -/* DT W O */{SST(0x14, 0x05, SS_RDEF, - "Record not found - recommend reassignment") }, -/* DT W O */{SST(0x14, 0x06, SS_RDEF, - "Record not found - data auto-reallocated") }, -/* DTL WRSOM */{SST(0x15, 0x00, SS_RDEF, - "Random positioning error") }, -/* DTL WRSOM */{SST(0x15, 0x01, SS_RDEF, - "Mechanical positioning error") }, -/* DT WR O */{SST(0x15, 0x02, SS_RDEF, - "Positioning error detected by read of medium") }, -/* D W O */{SST(0x16, 0x00, SS_RDEF, - "Data synchronization mark error") }, -/* D W O */{SST(0x16, 0x01, SS_RDEF, - "Data sync error - data rewritten") }, -/* D W O */{SST(0x16, 0x02, SS_RDEF, - "Data sync error - recommend rewrite") }, -/* D W O */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Data sync error - data auto-reallocated") }, -/* D W O */{SST(0x16, 0x04, SS_RDEF, - "Data sync error - recommend reassignment") }, -/* DT WRSO */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with no error correction applied") }, -/* DT WRSO */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with retries") }, -/* DT WR O */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with positive head offset") }, -/* DT WR O */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with negative head offset") }, -/* WR O */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with retries and/or CIRC applied") }, -/* D WR O */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data using previous sector id") }, -/* D W O */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - data auto-reallocated") }, -/* D W O */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - recommend reassignment")}, -/* D W O */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - recommend rewrite") }, -/* D W O */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - data rewritten") }, -/* D W O */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with error correction applied") }, -/* D WR O */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with error corr. & retries applied") }, -/* D WR O */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - data auto-reallocated") }, -/* R */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with CIRC") }, -/* R */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with L-EC") }, -/* D WR O */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - recommend reassignment") }, -/* D WR O */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - recommend rewrite") }, -/* D W O */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with ECC - data rewritten") }, -/* D O */{SST(0x19, 0x00, SS_RDEF, - "Defect list error") }, -/* D O */{SST(0x19, 0x01, SS_RDEF, - "Defect list not available") }, -/* D O */{SST(0x19, 0x02, SS_RDEF, - "Defect list error in primary list") }, -/* D O */{SST(0x19, 0x03, SS_RDEF, - "Defect list error in grown list") }, -/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF, - "Parameter list length error") }, -/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF, - "Synchronous data transfer error") }, -/* D O */{SST(0x1C, 0x00, SS_RDEF, - "Defect list not found") }, -/* D O */{SST(0x1C, 0x01, SS_RDEF, - "Primary defect list not found") }, -/* D O */{SST(0x1C, 0x02, SS_RDEF, - "Grown defect list not found") }, -/* D W O */{SST(0x1D, 0x00, SS_FATAL, - "Miscompare during verify operation" )}, -/* D W O */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered id with ecc correction") }, -/* D O */{SST(0x1F, 0x00, SS_RDEF, - "Partial defect list transfer") }, -/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL, - "Invalid command operation code") }, -/* DT WR OM */{SST(0x21, 0x00, SS_FATAL|EINVAL, - "Logical block address out of range" )}, -/* DT WR OM */{SST(0x21, 0x01, SS_FATAL|EINVAL, - "Invalid element address") }, -/* D */{SST(0x22, 0x00, SS_FATAL|EINVAL, - "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */ -/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL, - "Invalid field in CDB") }, -/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO, - "Logical unit not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL, - "Invalid field in parameter list") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL, - "Parameter not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL, - "Parameter value invalid") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL, - "Threshold parameters not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL, - "Invalid release of active persistent reservation") }, -/* DT W O */{SST(0x27, 0x00, SS_FATAL|EACCES, - "Write protected") }, -/* DT W O */{SST(0x27, 0x01, SS_FATAL|EACCES, - "Hardware write protected") }, -/* DT W O */{SST(0x27, 0x02, SS_FATAL|EACCES, - "Logical unit software write protected") }, -/* T */{SST(0x27, 0x03, SS_FATAL|EACCES, - "Associated write protect") }, -/* T */{SST(0x27, 0x04, SS_FATAL|EACCES, - "Persistent write protect") }, -/* T */{SST(0x27, 0x05, SS_FATAL|EACCES, - "Permanent write protect") }, -/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_RDEF, - "Not ready to ready change, medium may have changed") }, -/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO, - "Import or export element accessed") }, -/* - * XXX JGibbs - All of these should use the same errno, but I don't think - * ENXIO is the correct choice. Should we borrow from the networking - * errnos? ECONNRESET anyone? - */ -/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_RDEF, - "Power on, reset, or bus device reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF, - "Power on occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF, - "Scsi bus reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF, - "Bus device reset function occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF, - "Device internal reset") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF, - "Transceiver mode changed to single-ended") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF, - "Transceiver mode changed to LVD") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF, - "Parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF, - "Mode parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF, - "Log parameters changed") }, -/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF, - "Reservations preempted") }, -/* DTLPWRSO C */{SST(0x2B, 0x00, SS_RDEF, - "Copy cannot execute since host cannot disconnect") }, -/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF, - "Command sequence error") }, -/* S */{SST(0x2C, 0x01, SS_RDEF, - "Too many windows specified") }, -/* S */{SST(0x2C, 0x02, SS_RDEF, - "Invalid combination of windows specified") }, -/* R */{SST(0x2C, 0x03, SS_RDEF, - "Current program area is not empty") }, -/* R */{SST(0x2C, 0x04, SS_RDEF, - "Current program area is empty") }, -/* T */{SST(0x2D, 0x00, SS_RDEF, - "Overwrite error on update in place") }, -/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF, - "Commands cleared by another initiator") }, -/* DT WR OM */{SST(0x30, 0x00, SS_RDEF, - "Incompatible medium installed") }, -/* DT WR O */{SST(0x30, 0x01, SS_RDEF, - "Cannot read medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x02, SS_RDEF, - "Cannot read medium - incompatible format") }, -/* DT */{SST(0x30, 0x03, SS_RDEF, - "Cleaning cartridge installed") }, -/* DT WR O */{SST(0x30, 0x04, SS_RDEF, - "Cannot write medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x05, SS_RDEF, - "Cannot write medium - incompatible format") }, -/* DT W O */{SST(0x30, 0x06, SS_RDEF, - "Cannot format medium - incompatible medium") }, -/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF, - "Cleaning failure") }, -/* R */{SST(0x30, 0x08, SS_RDEF, - "Cannot write - application code mismatch") }, -/* R */{SST(0x30, 0x09, SS_RDEF, - "Current session not fixated for append") }, -/* DT WR O */{SST(0x31, 0x00, SS_RDEF, - "Medium format corrupted") }, -/* D L R O */{SST(0x31, 0x01, SS_RDEF, - "Format command failed") }, -/* D W O */{SST(0x32, 0x00, SS_RDEF, - "No defect spare location available") }, -/* D W O */{SST(0x32, 0x01, SS_RDEF, - "Defect list update failure") }, -/* T */{SST(0x33, 0x00, SS_RDEF, - "Tape length error") }, -/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF, - "Enclosure failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF, - "Enclosure services failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF, - "Unsupported enclosure function") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF, - "Enclosure services unavailable") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF, - "Enclosure services transfer failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF, - "Enclosure services transfer refused") }, -/* L */{SST(0x36, 0x00, SS_RDEF, - "Ribbon, ink, or toner failure") }, -/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF, - "Rounded parameter") }, -/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF, - "Saving parameters not supported") }, -/* DTL WRSOM */{SST(0x3A, 0x00, SS_NOP, - "Medium not present") }, -/* DT WR OM */{SST(0x3A, 0x01, SS_NOP, - "Medium not present - tray closed") }, -/* DT WR OM */{SST(0x3A, 0x01, SS_NOP, - "Medium not present - tray open") }, -/* DT WR OM */{SST(0x3A, 0x03, SS_NOP, - "Medium not present - Loadable") }, -/* DT WR OM */{SST(0x3A, 0x04, SS_NOP, - "Medium not present - medium auxiliary " - "memory accessible") }, -/* DT WR OM */{SST(0x3A, 0xFF, SS_NOP, NULL) },/* Range 0x05->0xFF */ -/* TL */{SST(0x3B, 0x00, SS_RDEF, - "Sequential positioning error") }, -/* T */{SST(0x3B, 0x01, SS_RDEF, - "Tape position error at beginning-of-medium") }, -/* T */{SST(0x3B, 0x02, SS_RDEF, - "Tape position error at end-of-medium") }, -/* L */{SST(0x3B, 0x03, SS_RDEF, - "Tape or electronic vertical forms unit not ready") }, -/* L */{SST(0x3B, 0x04, SS_RDEF, - "Slew failure") }, -/* L */{SST(0x3B, 0x05, SS_RDEF, - "Paper jam") }, -/* L */{SST(0x3B, 0x06, SS_RDEF, - "Failed to sense top-of-form") }, -/* L */{SST(0x3B, 0x07, SS_RDEF, - "Failed to sense bottom-of-form") }, -/* T */{SST(0x3B, 0x08, SS_RDEF, - "Reposition error") }, -/* S */{SST(0x3B, 0x09, SS_RDEF, - "Read past end of medium") }, -/* S */{SST(0x3B, 0x0A, SS_RDEF, - "Read past beginning of medium") }, -/* S */{SST(0x3B, 0x0B, SS_RDEF, - "Position past end of medium") }, -/* T S */{SST(0x3B, 0x0C, SS_RDEF, - "Position past beginning of medium") }, -/* DT WR OM */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC, - "Medium destination element full") }, -/* DT WR OM */{SST(0x3B, 0x0E, SS_RDEF, - "Medium source element empty") }, -/* R */{SST(0x3B, 0x0F, SS_RDEF, - "End of medium reached") }, -/* DT WR OM */{SST(0x3B, 0x11, SS_RDEF, - "Medium magazine not accessible") }, -/* DT WR OM */{SST(0x3B, 0x12, SS_RDEF, - "Medium magazine removed") }, -/* DT WR OM */{SST(0x3B, 0x13, SS_RDEF, - "Medium magazine inserted") }, -/* DT WR OM */{SST(0x3B, 0x14, SS_RDEF, - "Medium magazine locked") }, -/* DT WR OM */{SST(0x3B, 0x15, SS_RDEF, - "Medium magazine unlocked") }, -/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF, - "Invalid bits in identify message") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF, - "Logical unit has not self-configured yet") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF, - "Logical unit failure") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF, - "Timeout on logical unit") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF, - "Target operating conditions have changed") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF, - "Microcode has been changed") }, -/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_RDEF, - "Changed operating definition") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_INQ_REFRESH|SSQ_DECREMENT_COUNT, - "Inquiry data has changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x04, SS_RDEF, - "Component device attached") }, -/* DT WR OMCAE */{SST(0x3F, 0x05, SS_RDEF, - "Device identifier changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x06, SS_RDEF, - "Redundancy group created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x07, SS_RDEF, - "Redundancy group deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x08, SS_RDEF, - "Spare created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x09, SS_RDEF, - "Spare deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF, - "Volume set created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF, - "Volume set deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF, - "Volume set deassigned") }, -/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF, - "Volume set reassigned") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x0E, SS_RDEF, - "Reported luns data has changed") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x0F, SS_RETRY|SSQ_DECREMENT_COUNT - | SSQ_DELAY_RANDOM|EBUSY, - "Echo buffer overwritten") }, -/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF, "Medium Loadable") }, -/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF, - "Medium auxiliary memory accessible") }, -/* D */{SST(0x40, 0x00, SS_RDEF, - "Ram failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF, - "Diagnostic failure: ASCQ = Component ID") }, -/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) },/* Range 0x80->0xFF */ -/* D */{SST(0x41, 0x00, SS_RDEF, - "Data path failure") }, /* deprecated - use 40 NN instead */ -/* D */{SST(0x42, 0x00, SS_RDEF, - "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF, - "Message error") }, -/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF, - "Internal target failure") }, -/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF, - "Select or reselect failure") }, -/* DTLPWRSOMC */{SST(0x46, 0x00, SS_RDEF, - "Unsuccessful soft reset") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF|SSQ_FALLBACK, - "SCSI parity error") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x01, SS_RDEF|SSQ_FALLBACK, - "Data Phase CRC error detected") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x02, SS_RDEF|SSQ_FALLBACK, - "SCSI parity error detected during ST data phase") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x03, SS_RDEF|SSQ_FALLBACK, - "Information Unit iuCRC error") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x04, SS_RDEF|SSQ_FALLBACK, - "Asynchronous information protection error detected") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x05, SS_RDEF|SSQ_FALLBACK, - "Protocol server CRC error") }, -/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF|SSQ_FALLBACK, - "Initiator detected error message received") }, -/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF, - "Invalid message error") }, -/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF, - "Command phase error") }, -/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF, - "Data phase error") }, -/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF, - "Logical unit failed self-configuration") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF, - "Tagged overlapped commands: ASCQ = Queue tag ID") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE, - NULL)}, /* Range 0x00->0xFF */ -/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF, - "Overlapped commands attempted") }, -/* T */{SST(0x50, 0x00, SS_RDEF, - "Write append error") }, -/* T */{SST(0x50, 0x01, SS_RDEF, - "Write append position error") }, -/* T */{SST(0x50, 0x02, SS_RDEF, - "Position error related to timing") }, -/* T O */{SST(0x51, 0x00, SS_RDEF, - "Erase failure") }, -/* T */{SST(0x52, 0x00, SS_RDEF, - "Cartridge fault") }, -/* DTL WRSOM */{SST(0x53, 0x00, SS_RDEF, - "Media load or eject failed") }, -/* T */{SST(0x53, 0x01, SS_RDEF, - "Unload tape failure") }, -/* DT WR OM */{SST(0x53, 0x02, SS_RDEF, - "Medium removal prevented") }, -/* P */{SST(0x54, 0x00, SS_RDEF, - "Scsi to host system interface failure") }, -/* P */{SST(0x55, 0x00, SS_RDEF, - "System resource failure") }, -/* D O */{SST(0x55, 0x01, SS_FATAL|ENOSPC, - "System buffer full") }, -/* R */{SST(0x57, 0x00, SS_RDEF, - "Unable to recover table-of-contents") }, -/* O */{SST(0x58, 0x00, SS_RDEF, - "Generation does not exist") }, -/* O */{SST(0x59, 0x00, SS_RDEF, - "Updated block read") }, -/* DTLPWRSOM */{SST(0x5A, 0x00, SS_RDEF, - "Operator request or state change input") }, -/* DT WR OM */{SST(0x5A, 0x01, SS_RDEF, - "Operator medium removal request") }, -/* DT W O */{SST(0x5A, 0x02, SS_RDEF, - "Operator selected write protect") }, -/* DT W O */{SST(0x5A, 0x03, SS_RDEF, - "Operator selected write permit") }, -/* DTLPWRSOM */{SST(0x5B, 0x00, SS_RDEF, - "Log exception") }, -/* DTLPWRSOM */{SST(0x5B, 0x01, SS_RDEF, - "Threshold condition met") }, -/* DTLPWRSOM */{SST(0x5B, 0x02, SS_RDEF, - "Log counter at maximum") }, -/* DTLPWRSOM */{SST(0x5B, 0x03, SS_RDEF, - "Log list codes exhausted") }, -/* D O */{SST(0x5C, 0x00, SS_RDEF, - "RPL status change") }, -/* D O */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Spindles synchronized") }, -/* D O */{SST(0x5C, 0x02, SS_RDEF, - "Spindles not synchronized") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF, - "Failure prediction threshold exceeded") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF, - "Failure prediction threshold exceeded (false)") }, -/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_RDEF, - "Low power condition on") }, -/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_RDEF, - "Idle condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_RDEF, - "Standby condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_RDEF, - "Idle condition activated by command") }, -/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_RDEF, - "Standby condition activated by command") }, -/* S */{SST(0x60, 0x00, SS_RDEF, - "Lamp failure") }, -/* S */{SST(0x61, 0x00, SS_RDEF, - "Video acquisition error") }, -/* S */{SST(0x61, 0x01, SS_RDEF, - "Unable to acquire video") }, -/* S */{SST(0x61, 0x02, SS_RDEF, - "Out of focus") }, -/* S */{SST(0x62, 0x00, SS_RDEF, - "Scan head positioning error") }, -/* R */{SST(0x63, 0x00, SS_RDEF, - "End of user area encountered on this track") }, -/* R */{SST(0x63, 0x01, SS_FATAL|ENOSPC, - "Packet does not fit in available space") }, -/* R */{SST(0x64, 0x00, SS_RDEF, - "Illegal mode for this track") }, -/* R */{SST(0x64, 0x01, SS_RDEF, - "Invalid packet size") }, -/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF, - "Voltage fault") }, -/* S */{SST(0x66, 0x00, SS_RDEF, - "Automatic document feeder cover up") }, -/* S */{SST(0x66, 0x01, SS_RDEF, - "Automatic document feeder lift up") }, -/* S */{SST(0x66, 0x02, SS_RDEF, - "Document jam in automatic document feeder") }, -/* S */{SST(0x66, 0x03, SS_RDEF, - "Document miss feed automatic in document feeder") }, -/* A */{SST(0x67, 0x00, SS_RDEF, - "Configuration failure") }, -/* A */{SST(0x67, 0x01, SS_RDEF, - "Configuration of incapable logical units failed") }, -/* A */{SST(0x67, 0x02, SS_RDEF, - "Add logical unit failed") }, -/* A */{SST(0x67, 0x03, SS_RDEF, - "Modification of logical unit failed") }, -/* A */{SST(0x67, 0x04, SS_RDEF, - "Exchange of logical unit failed") }, -/* A */{SST(0x67, 0x05, SS_RDEF, - "Remove of logical unit failed") }, -/* A */{SST(0x67, 0x06, SS_RDEF, - "Attachment of logical unit failed") }, -/* A */{SST(0x67, 0x07, SS_RDEF, - "Creation of logical unit failed") }, -/* A */{SST(0x68, 0x00, SS_RDEF, - "Logical unit not configured") }, -/* A */{SST(0x69, 0x00, SS_RDEF, - "Data loss on logical unit") }, -/* A */{SST(0x69, 0x01, SS_RDEF, - "Multiple logical unit failures") }, -/* A */{SST(0x69, 0x02, SS_RDEF, - "Parity/data mismatch") }, -/* A */{SST(0x6A, 0x00, SS_RDEF, - "Informational, refer to log") }, -/* A */{SST(0x6B, 0x00, SS_RDEF, - "State change has occurred") }, -/* A */{SST(0x6B, 0x01, SS_RDEF, - "Redundancy level got better") }, -/* A */{SST(0x6B, 0x02, SS_RDEF, - "Redundancy level got worse") }, -/* A */{SST(0x6C, 0x00, SS_RDEF, - "Rebuild failure occurred") }, -/* A */{SST(0x6D, 0x00, SS_RDEF, - "Recalculate failure occurred") }, -/* A */{SST(0x6E, 0x00, SS_RDEF, - "Command to logical unit failed") }, -/* T */{SST(0x70, 0x00, SS_RDEF, - "Decompression exception short: ASCQ = Algorithm ID") }, -/* T */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) }, /* Range 0x00 -> 0xFF */ -/* T */{SST(0x71, 0x00, SS_RDEF, - "Decompression exception long: ASCQ = Algorithm ID") }, -/* T */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) }, /* Range 0x00 -> 0xFF */ -/* R */{SST(0x72, 0x00, SS_RDEF, - "Session fixation error") }, -/* R */{SST(0x72, 0x01, SS_RDEF, - "Session fixation error writing lead-in") }, -/* R */{SST(0x72, 0x02, SS_RDEF, - "Session fixation error writing lead-out") }, -/* R */{SST(0x72, 0x03, SS_RDEF, - "Session fixation error - incomplete track in session") }, -/* R */{SST(0x72, 0x04, SS_RDEF, - "Empty or partially written reserved track") }, -/* R */{SST(0x73, 0x00, SS_RDEF, - "CD control error") }, -/* R */{SST(0x73, 0x01, SS_RDEF, - "Power calibration area almost full") }, -/* R */{SST(0x73, 0x02, SS_FATAL|ENOSPC, - "Power calibration area is full") }, -/* R */{SST(0x73, 0x03, SS_RDEF, - "Power calibration area error") }, -/* R */{SST(0x73, 0x04, SS_RDEF, - "Program memory area update failure") }, -/* R */{SST(0x73, 0x05, SS_RDEF, - "program memory area is full") } -}; - -static const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); - -struct asc_key -{ - int asc; - int ascq; -}; - -static int -ascentrycomp(const void *key, const void *member) -{ - int asc; - int ascq; - const struct asc_table_entry *table_entry; - - asc = ((const struct asc_key *)key)->asc; - ascq = ((const struct asc_key *)key)->ascq; - table_entry = (const struct asc_table_entry *)member; - - if (asc >= table_entry->asc) { - - if (asc > table_entry->asc) - return (1); - - if (ascq <= table_entry->ascq) { - /* Check for ranges */ - if (ascq == table_entry->ascq - || ((table_entry->action & SSQ_RANGE) != 0 - && ascq >= (table_entry - 1)->ascq)) - return (0); - return (-1); - } - return (1); - } - return (-1); -} - -static int -senseentrycomp(const void *key, const void *member) -{ - int sense_key; - const struct sense_key_table_entry *table_entry; - - sense_key = *((const int *)key); - table_entry = (const struct sense_key_table_entry *)member; - - if (sense_key >= table_entry->sense_key) { - if (sense_key == table_entry->sense_key) - return (0); - return (1); - } - return (-1); -} - -static void -fetchtableentries(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *inq_data, - const struct sense_key_table_entry **sense_entry, - const struct asc_table_entry **asc_entry) -{ - void *match; - const struct asc_table_entry *asc_tables[2]; - const struct sense_key_table_entry *sense_tables[2]; - struct asc_key asc_ascq; - size_t asc_tables_size[2]; - size_t sense_tables_size[2]; - int num_asc_tables; - int num_sense_tables; - int i; - - /* Default to failure */ - *sense_entry = NULL; - *asc_entry = NULL; - match = NULL; - if (inq_data != NULL) - match = cam_quirkmatch((void *)inq_data, - (void *)sense_quirk_table, - sense_quirk_table_size, - sizeof(*sense_quirk_table), - aic_inquiry_match); - - if (match != NULL) { - struct scsi_sense_quirk_entry *quirk; - - quirk = (struct scsi_sense_quirk_entry *)match; - asc_tables[0] = quirk->asc_info; - asc_tables_size[0] = quirk->num_ascs; - asc_tables[1] = asc_table; - asc_tables_size[1] = asc_table_size; - num_asc_tables = 2; - sense_tables[0] = quirk->sense_key_info; - sense_tables_size[0] = quirk->num_sense_keys; - sense_tables[1] = sense_key_table; - sense_tables_size[1] = sense_key_table_size; - num_sense_tables = 2; - } else { - asc_tables[0] = asc_table; - asc_tables_size[0] = asc_table_size; - num_asc_tables = 1; - sense_tables[0] = sense_key_table; - sense_tables_size[0] = sense_key_table_size; - num_sense_tables = 1; - } - - asc_ascq.asc = asc; - asc_ascq.ascq = ascq; - for (i = 0; i < num_asc_tables; i++) { - void *found_entry; - - found_entry = scsibsearch(&asc_ascq, asc_tables[i], - asc_tables_size[i], - sizeof(**asc_tables), - ascentrycomp); - - if (found_entry) { - *asc_entry = (struct asc_table_entry *)found_entry; - break; - } - } - - for (i = 0; i < num_sense_tables; i++) { - void *found_entry; - - found_entry = scsibsearch(&sense_key, sense_tables[i], - sense_tables_size[i], - sizeof(**sense_tables), - senseentrycomp); - - if (found_entry) { - *sense_entry = - (struct sense_key_table_entry *)found_entry; - break; - } - } -} - -static void * -scsibsearch(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) -{ - const void *entry; - u_int l; - u_int u; - u_int m; - - l = -1; - u = nmemb; - while (l + 1 != u) { - m = (l + u) / 2; - entry = base + m * size; - if (compar(key, entry) > 0) - l = m; - else - u = m; - } - - entry = base + u * size; - if (u == nmemb - || compar(key, entry) != 0) - return (NULL); - return ((void *)entry); -} - -/* - * Compare string with pattern, returning 0 on match. - * Short pattern matches trailing blanks in name, - * wildcard '*' in pattern matches rest of name, - * wildcard '?' matches a single non-space character. - */ -static int -cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len) -{ - - while (*pattern != '\0'&& str_len > 0) { - - if (*pattern == '*') { - return (0); - } - if ((*pattern != *str) - && (*pattern != '?' || *str == ' ')) { - return (1); - } - pattern++; - str++; - str_len--; - } - while (str_len > 0 && *str++ == ' ') - str_len--; - - return (str_len); -} - -static caddr_t -cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, - int entry_size, cam_quirkmatch_t *comp_func) -{ - for (; num_entries > 0; num_entries--, quirk_table += entry_size) { - if ((*comp_func)(target, quirk_table) == 0) - return (quirk_table); - } - return (NULL); -} - -void -aic_sense_desc(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *inq_data, - const char **sense_key_desc, const char **asc_desc) -{ - const struct asc_table_entry *asc_entry; - const struct sense_key_table_entry *sense_entry; - - fetchtableentries(sense_key, asc, ascq, - inq_data, - &sense_entry, - &asc_entry); - - *sense_key_desc = sense_entry->desc; - - if (asc_entry != NULL) - *asc_desc = asc_entry->desc; - else if (asc >= 0x80 && asc <= 0xff) - *asc_desc = "Vendor Specific ASC"; - else if (ascq >= 0x80 && ascq <= 0xff) - *asc_desc = "Vendor Specific ASCQ"; - else - *asc_desc = "Reserved ASC/ASCQ pair"; -} - -/* - * Given sense and device type information, return the appropriate action. - * If we do not understand the specific error as identified by the ASC/ASCQ - * pair, fall back on the more generic actions derived from the sense key. - */ -aic_sense_action -aic_sense_error_action(struct scsi_sense_data *sense_data, - struct scsi_inquiry_data *inq_data, uint32_t sense_flags) -{ - const struct asc_table_entry *asc_entry; - const struct sense_key_table_entry *sense_entry; - int error_code, sense_key, asc, ascq; - aic_sense_action action; - - scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); - - if (error_code == SSD_DEFERRED_ERROR) { - /* - * XXX dufault@FreeBSD.org - * This error doesn't relate to the command associated - * with this request sense. A deferred error is an error - * for a command that has already returned GOOD status - * (see SCSI2 8.2.14.2). - * - * By my reading of that section, it looks like the current - * command has been cancelled, we should now clean things up - * (hopefully recovering any lost data) and then retry the - * current command. There are two easy choices, both wrong: - * - * 1. Drop through (like we had been doing), thus treating - * this as if the error were for the current command and - * return and stop the current command. - * - * 2. Issue a retry (like I made it do) thus hopefully - * recovering the current transfer, and ignoring the - * fact that we've dropped a command. - * - * These should probably be handled in a device specific - * sense handler or punted back up to a user mode daemon - */ - action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; - } else { - fetchtableentries(sense_key, asc, ascq, - inq_data, - &sense_entry, - &asc_entry); - - /* - * Override the 'No additional Sense' entry (0,0) - * with the error action of the sense key. - */ - if (asc_entry != NULL - && (asc != 0 || ascq != 0)) - action = asc_entry->action; - else - action = sense_entry->action; - - if (sense_key == SSD_KEY_RECOVERED_ERROR) { - /* - * The action succeeded but the device wants - * the user to know that some recovery action - * was required. - */ - action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); - action |= SS_NOP|SSQ_PRINT_SENSE; - } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { - if ((sense_flags & SF_QUIET_IR) != 0) - action &= ~SSQ_PRINT_SENSE; - } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { - if ((sense_flags & SF_RETRY_UA) != 0 - && (action & SS_MASK) == SS_FAIL) { - action &= ~(SS_MASK|SSQ_MASK); - action |= SS_RETRY|SSQ_DECREMENT_COUNT| - SSQ_PRINT_SENSE; - } - } - } - - if ((sense_flags & SF_PRINT_ALWAYS) != 0) - action |= SSQ_PRINT_SENSE; - else if ((sense_flags & SF_NO_PRINT) != 0) - action &= ~SSQ_PRINT_SENSE; - - return (action); -} - -/* - * Try make as good a match as possible with - * available sub drivers - */ -int -aic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) -{ - struct scsi_inquiry_pattern *entry; - struct scsi_inquiry_data *inq; - - entry = (struct scsi_inquiry_pattern *)table_entry; - inq = (struct scsi_inquiry_data *)inqbuffer; - - if (((SID_TYPE(inq) == entry->type) - || (entry->type == T_ANY)) - && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE - : entry->media_type & SIP_MEDIA_FIXED) - && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) - && (cam_strmatch(inq->product, entry->product, - sizeof(inq->product)) == 0) - && (cam_strmatch(inq->revision, entry->revision, - sizeof(inq->revision)) == 0)) { - return (0); - } - return (-1); -} /* * Table of syncrates that don't follow the "divisible by 4" @@ -1229,108 +75,6 @@ aic_calc_syncsrate(u_int period_factor) return (10000000 / (period_factor * 4 * 10)); } -/* - * Return speed in KB/s. - */ -u_int -aic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate) -{ - u_int freq; - - if (offset != 0 && period < min_rate) - freq = aic_calc_syncsrate(period); - else - /* Roughly 3.3MB/s for async */ - freq = 3300; - freq <<= width; - return (freq); -} - -uint32_t -aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data, - cam_status status, u_int scsi_status) -{ - aic_sense_action err_action; - int sense; - - sense = (cmd->result >> 24) == DRIVER_SENSE; - - switch (status) { - case CAM_REQ_CMP: - err_action = SS_NOP; - break; - case CAM_AUTOSENSE_FAIL: - case CAM_SCSI_STATUS_ERROR: - - switch (scsi_status) { - case SCSI_STATUS_OK: - case SCSI_STATUS_COND_MET: - case SCSI_STATUS_INTERMED: - case SCSI_STATUS_INTERMED_COND_MET: - err_action = SS_NOP; - break; - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - if (sense != 0) { - struct scsi_sense_data *sense; - - sense = (struct scsi_sense_data *) - &cmd->sense_buffer; - err_action = - aic_sense_error_action(sense, inq_data, 0); - - } else { - err_action = SS_RETRY|SSQ_FALLBACK - | SSQ_DECREMENT_COUNT|EIO; - } - break; - case SCSI_STATUS_QUEUE_FULL: - case SCSI_STATUS_BUSY: - err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY - | SSQ_DECREMENT_COUNT|EBUSY; - break; - case SCSI_STATUS_RESERV_CONFLICT: - default: - err_action = SS_FAIL|EBUSY; - break; - } - break; - case CAM_CMD_TIMEOUT: - case CAM_REQ_CMP_ERR: - case CAM_UNEXP_BUSFREE: - case CAM_UNCOR_PARITY: - case CAM_DATA_RUN_ERR: - err_action = SS_RETRY|SSQ_FALLBACK|EIO; - break; - case CAM_UA_ABORT: - case CAM_UA_TERMIO: - case CAM_MSG_REJECT_REC: - case CAM_SEL_TIMEOUT: - err_action = SS_FAIL|EIO; - break; - case CAM_REQ_INVALID: - case CAM_PATH_INVALID: - case CAM_DEV_NOT_THERE: - case CAM_NO_HBA: - case CAM_PROVIDE_FAIL: - case CAM_REQ_TOO_BIG: - case CAM_RESRC_UNAVAIL: - case CAM_BUSY: - default: - /* panic?? These should never occur in our application. */ - err_action = SS_FAIL|EIO; - break; - case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: - case CAM_REQUEUE_REQ: - /* Unconditional requeue */ - err_action = SS_RETRY; - break; - } - - return (err_action); -} - char * aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, aic_option_callback_t *callback, u_long callback_arg) diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index bfe6f954d3c..e7d94cbaf2a 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -57,121 +57,6 @@ #ifndef _AICLIB_H #define _AICLIB_H -/* - * Linux Interrupt Support. - */ -#ifndef IRQ_RETVAL -typedef void irqreturn_t; -#define IRQ_RETVAL(x) -#endif - -/* - * SCSI command format - */ - -/* - * Define dome bits that are in ALL (or a lot of) scsi commands - */ -#define SCSI_CTL_LINK 0x01 -#define SCSI_CTL_FLAG 0x02 -#define SCSI_CTL_VENDOR 0xC0 -#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */ -#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */ - -#define SCSI_MAX_CDBLEN 16 /* - * 16 byte commands are in the - * SCSI-3 spec - */ -/* 6byte CDBs special case 0 length to be 256 */ -#define SCSI_CDB6_LEN(len) ((len) == 0 ? 256 : len) - -/* - * This type defines actions to be taken when a particular sense code is - * received. Right now, these flags are only defined to take up 16 bits, - * but can be expanded in the future if necessary. - */ -typedef enum { - SS_NOP = 0x000000, /* Do nothing */ - SS_RETRY = 0x010000, /* Retry the command */ - SS_FAIL = 0x020000, /* Bail out */ - SS_START = 0x030000, /* Send a Start Unit command to the device, - * then retry the original command. - */ - SS_TUR = 0x040000, /* Send a Test Unit Ready command to the - * device, then retry the original command. - */ - SS_REQSENSE = 0x050000, /* Send a RequestSense command to the - * device, then retry the original command. - */ - SS_INQ_REFRESH = 0x060000, - SS_MASK = 0xff0000 -} aic_sense_action; - -typedef enum { - SSQ_NONE = 0x0000, - SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */ - SSQ_MANY = 0x0200, /* send lots of recovery commands */ - SSQ_RANGE = 0x0400, /* - * This table entry represents the - * end of a range of ASCQs that - * have identical error actions - * and text. - */ - SSQ_PRINT_SENSE = 0x0800, - SSQ_DELAY = 0x1000, /* Delay before retry. */ - SSQ_DELAY_RANDOM = 0x2000, /* Randomized delay before retry. */ - SSQ_FALLBACK = 0x4000, /* Do a speed fallback to recover */ - SSQ_MASK = 0xff00 -} aic_sense_action_qualifier; - -/* Mask for error status values */ -#define SS_ERRMASK 0xff - -/* The default, retyable, error action */ -#define SS_RDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO - -/* The retyable, error action, with table specified error code */ -#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE - -/* Fatal error action, with table specified error code */ -#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE - -struct scsi_generic -{ - uint8_t opcode; - uint8_t bytes[11]; -}; - -struct scsi_request_sense -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_test_unit_ready -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[3]; - uint8_t control; -}; - -struct scsi_send_diag -{ - uint8_t opcode; - uint8_t byte2; -#define SSD_UOL 0x01 -#define SSD_DOL 0x02 -#define SSD_SELFTEST 0x04 -#define SSD_PF 0x10 - uint8_t unused[1]; - uint8_t paramlen[2]; - uint8_t control; -}; - struct scsi_sense { uint8_t opcode; @@ -181,537 +66,12 @@ struct scsi_sense uint8_t control; }; -struct scsi_inquiry -{ - uint8_t opcode; - uint8_t byte2; -#define SI_EVPD 0x01 - uint8_t page_code; - uint8_t reserved; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_sense_6 -{ - uint8_t opcode; - uint8_t byte2; -#define SMS_DBD 0x08 - uint8_t page; -#define SMS_PAGE_CODE 0x3F -#define SMS_VENDOR_SPECIFIC_PAGE 0x00 -#define SMS_DISCONNECT_RECONNECT_PAGE 0x02 -#define SMS_PERIPHERAL_DEVICE_PAGE 0x09 -#define SMS_CONTROL_MODE_PAGE 0x0A -#define SMS_ALL_PAGES_PAGE 0x3F -#define SMS_PAGE_CTRL_MASK 0xC0 -#define SMS_PAGE_CTRL_CURRENT 0x00 -#define SMS_PAGE_CTRL_CHANGEABLE 0x40 -#define SMS_PAGE_CTRL_DEFAULT 0x80 -#define SMS_PAGE_CTRL_SAVED 0xC0 - uint8_t unused; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_sense_10 -{ - uint8_t opcode; - uint8_t byte2; /* same bits as small version */ - uint8_t page; /* same bits as small version */ - uint8_t unused[4]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_mode_select_6 -{ - uint8_t opcode; - uint8_t byte2; -#define SMS_SP 0x01 -#define SMS_PF 0x10 - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_select_10 -{ - uint8_t opcode; - uint8_t byte2; /* same bits as small version */ - uint8_t unused[5]; - uint8_t length[2]; - uint8_t control; -}; - -/* - * When sending a mode select to a tape drive, the medium type must be 0. - */ -struct scsi_mode_hdr_6 -{ - uint8_t datalen; - uint8_t medium_type; - uint8_t dev_specific; - uint8_t block_descr_len; -}; - -struct scsi_mode_hdr_10 -{ - uint8_t datalen[2]; - uint8_t medium_type; - uint8_t dev_specific; - uint8_t reserved[2]; - uint8_t block_descr_len[2]; -}; - -struct scsi_mode_block_descr -{ - uint8_t density_code; - uint8_t num_blocks[3]; - uint8_t reserved; - uint8_t block_len[3]; -}; - -struct scsi_log_sense -{ - uint8_t opcode; - uint8_t byte2; -#define SLS_SP 0x01 -#define SLS_PPC 0x02 - uint8_t page; -#define SLS_PAGE_CODE 0x3F -#define SLS_ALL_PAGES_PAGE 0x00 -#define SLS_OVERRUN_PAGE 0x01 -#define SLS_ERROR_WRITE_PAGE 0x02 -#define SLS_ERROR_READ_PAGE 0x03 -#define SLS_ERROR_READREVERSE_PAGE 0x04 -#define SLS_ERROR_VERIFY_PAGE 0x05 -#define SLS_ERROR_NONMEDIUM_PAGE 0x06 -#define SLS_ERROR_LASTN_PAGE 0x07 -#define SLS_PAGE_CTRL_MASK 0xC0 -#define SLS_PAGE_CTRL_THRESHOLD 0x00 -#define SLS_PAGE_CTRL_CUMULATIVE 0x40 -#define SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 -#define SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 - uint8_t reserved[2]; - uint8_t paramptr[2]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_log_select -{ - uint8_t opcode; - uint8_t byte2; -/* SLS_SP 0x01 */ -#define SLS_PCR 0x02 - uint8_t page; -/* SLS_PAGE_CTRL_MASK 0xC0 */ -/* SLS_PAGE_CTRL_THRESHOLD 0x00 */ -/* SLS_PAGE_CTRL_CUMULATIVE 0x40 */ -/* SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 */ -/* SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 */ - uint8_t reserved[4]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_log_header -{ - uint8_t page; - uint8_t reserved; - uint8_t datalen[2]; -}; - -struct scsi_log_param_header { - uint8_t param_code[2]; - uint8_t param_control; -#define SLP_LP 0x01 -#define SLP_LBIN 0x02 -#define SLP_TMC_MASK 0x0C -#define SLP_TMC_ALWAYS 0x00 -#define SLP_TMC_EQUAL 0x04 -#define SLP_TMC_NOTEQUAL 0x08 -#define SLP_TMC_GREATER 0x0C -#define SLP_ETC 0x10 -#define SLP_TSD 0x20 -#define SLP_DS 0x40 -#define SLP_DU 0x80 - uint8_t param_len; -}; - -struct scsi_control_page { - uint8_t page_code; - uint8_t page_length; - uint8_t rlec; -#define SCB_RLEC 0x01 /*Report Log Exception Cond*/ - uint8_t queue_flags; -#define SCP_QUEUE_ALG_MASK 0xF0 -#define SCP_QUEUE_ALG_RESTRICTED 0x00 -#define SCP_QUEUE_ALG_UNRESTRICTED 0x10 -#define SCP_QUEUE_ERR 0x02 /*Queued I/O aborted for CACs*/ -#define SCP_QUEUE_DQUE 0x01 /*Queued I/O disabled*/ - uint8_t eca_and_aen; -#define SCP_EECA 0x80 /*Enable Extended CA*/ -#define SCP_RAENP 0x04 /*Ready AEN Permission*/ -#define SCP_UAAENP 0x02 /*UA AEN Permission*/ -#define SCP_EAENP 0x01 /*Error AEN Permission*/ - uint8_t reserved; - uint8_t aen_holdoff_period[2]; -}; - -struct scsi_reserve -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_release -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_prevent -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t how; - uint8_t control; -}; -#define PR_PREVENT 0x01 -#define PR_ALLOW 0x00 - -struct scsi_sync_cache -{ - uint8_t opcode; - uint8_t byte2; - uint8_t begin_lba[4]; - uint8_t reserved; - uint8_t lb_count[2]; - uint8_t control; -}; - - -struct scsi_changedef -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused1; - uint8_t how; - uint8_t unused[4]; - uint8_t datalen; - uint8_t control; -}; - -struct scsi_read_buffer -{ - uint8_t opcode; - uint8_t byte2; -#define RWB_MODE 0x07 -#define RWB_MODE_HDR_DATA 0x00 -#define RWB_MODE_DATA 0x02 -#define RWB_MODE_DOWNLOAD 0x04 -#define RWB_MODE_DOWNLOAD_SAVE 0x05 - uint8_t buffer_id; - uint8_t offset[3]; - uint8_t length[3]; - uint8_t control; -}; - -struct scsi_write_buffer -{ - uint8_t opcode; - uint8_t byte2; - uint8_t buffer_id; - uint8_t offset[3]; - uint8_t length[3]; - uint8_t control; -}; - -struct scsi_rw_6 -{ - uint8_t opcode; - uint8_t addr[3]; -/* only 5 bits are valid in the MSB address byte */ -#define SRW_TOPADDR 0x1F - uint8_t length; - uint8_t control; -}; - -struct scsi_rw_10 -{ - uint8_t opcode; -#define SRW10_RELADDR 0x01 -#define SRW10_FUA 0x08 -#define SRW10_DPO 0x10 - uint8_t byte2; - uint8_t addr[4]; - uint8_t reserved; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_rw_12 -{ - uint8_t opcode; -#define SRW12_RELADDR 0x01 -#define SRW12_FUA 0x08 -#define SRW12_DPO 0x10 - uint8_t byte2; - uint8_t addr[4]; - uint8_t length[4]; - uint8_t reserved; - uint8_t control; -}; - -struct scsi_start_stop_unit -{ - uint8_t opcode; - uint8_t byte2; -#define SSS_IMMED 0x01 - uint8_t reserved[2]; - uint8_t how; -#define SSS_START 0x01 -#define SSS_LOEJ 0x02 - uint8_t control; -}; - -#define SC_SCSI_1 0x01 -#define SC_SCSI_2 0x03 - -/* - * Opcodes - */ - -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define READ_6 0x08 -#define WRITE_6 0x0a -#define INQUIRY 0x12 -#define MODE_SELECT_6 0x15 -#define MODE_SENSE_6 0x1a -#define START_STOP_UNIT 0x1b -#define START_STOP 0x1b -#define RESERVE 0x16 -#define RELEASE 0x17 -#define RECEIVE_DIAGNOSTIC 0x1c -#define SEND_DIAGNOSTIC 0x1d -#define PREVENT_ALLOW 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define WRITE_10 0x2a -#define POSITION_TO_ELEMENT 0x2b -#define SYNCHRONIZE_CACHE 0x35 -#define WRITE_BUFFER 0x3b -#define READ_BUFFER 0x3c -#define CHANGE_DEFINITION 0x40 -#define LOG_SELECT 0x4c -#define LOG_SENSE 0x4d -#ifdef XXXCAM -#define MODE_SENSE_10 0x5A -#endif -#define MODE_SELECT_10 0x55 -#define MOVE_MEDIUM 0xa5 -#define READ_12 0xa8 -#define WRITE_12 0xaa -#define READ_ELEMENT_STATUS 0xb8 - - -/* - * Device Types - */ -#define T_DIRECT 0x00 -#define T_SEQUENTIAL 0x01 -#define T_PRINTER 0x02 -#define T_PROCESSOR 0x03 -#define T_WORM 0x04 -#define T_CDROM 0x05 -#define T_SCANNER 0x06 -#define T_OPTICAL 0x07 -#define T_CHANGER 0x08 -#define T_COMM 0x09 -#define T_ASC0 0x0a -#define T_ASC1 0x0b -#define T_STORARRAY 0x0c -#define T_ENCLOSURE 0x0d -#define T_RBC 0x0e -#define T_OCRW 0x0f -#define T_NODEVICE 0x1F -#define T_ANY 0xFF /* Used in Quirk table matches */ - -#define T_REMOV 1 -#define T_FIXED 0 - -/* - * This length is the initial inquiry length used by the probe code, as - * well as the legnth necessary for aic_print_inquiry() to function - * correctly. If either use requires a different length in the future, - * the two values should be de-coupled. - */ -#define SHORT_INQUIRY_LENGTH 36 - -struct scsi_inquiry_data -{ - uint8_t device; -#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f) -#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5) -#define SID_QUAL_LU_CONNECTED 0x00 /* - * The specified peripheral device - * type is currently connected to - * logical unit. If the target cannot - * determine whether or not a physical - * device is currently connected, it - * shall also use this peripheral - * qualifier when returning the INQUIRY - * data. This peripheral qualifier - * does not mean that the device is - * ready for access by the initiator. - */ -#define SID_QUAL_LU_OFFLINE 0x01 /* - * The target is capable of supporting - * the specified peripheral device type - * on this logical unit; however, the - * physical device is not currently - * connected to this logical unit. - */ -#define SID_QUAL_RSVD 0x02 -#define SID_QUAL_BAD_LU 0x03 /* - * The target is not capable of - * supporting a physical device on - * this logical unit. For this - * peripheral qualifier the peripheral - * device type shall be set to 1Fh to - * provide compatibility with previous - * versions of SCSI. All other - * peripheral device type values are - * reserved for this peripheral - * qualifier. - */ -#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0) - uint8_t dev_qual2; -#define SID_QUAL2 0x7F -#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0) - uint8_t version; -#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07) #define SCSI_REV_0 0 #define SCSI_REV_CCS 1 #define SCSI_REV_2 2 #define SCSI_REV_SPC 3 #define SCSI_REV_SPC2 4 -#define SID_ECMA 0x38 -#define SID_ISO 0xC0 - uint8_t response_format; -#define SID_AENC 0x80 -#define SID_TrmIOP 0x40 - uint8_t additional_length; - uint8_t reserved[2]; - uint8_t flags; -#define SID_SftRe 0x01 -#define SID_CmdQue 0x02 -#define SID_Linked 0x08 -#define SID_Sync 0x10 -#define SID_WBus16 0x20 -#define SID_WBus32 0x40 -#define SID_RelAdr 0x80 -#define SID_VENDOR_SIZE 8 - char vendor[SID_VENDOR_SIZE]; -#define SID_PRODUCT_SIZE 16 - char product[SID_PRODUCT_SIZE]; -#define SID_REVISION_SIZE 4 - char revision[SID_REVISION_SIZE]; - /* - * The following fields were taken from SCSI Primary Commands - 2 - * (SPC-2) Revision 14, Dated 11 November 1999 - */ -#define SID_VENDOR_SPECIFIC_0_SIZE 20 - uint8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE]; - /* - * An extension of SCSI Parallel Specific Values - */ -#define SID_SPI_IUS 0x01 -#define SID_SPI_QAS 0x02 -#define SID_SPI_CLOCK_ST 0x00 -#define SID_SPI_CLOCK_DT 0x04 -#define SID_SPI_CLOCK_DT_ST 0x0C -#define SID_SPI_MASK 0x0F - uint8_t spi3data; - uint8_t reserved2; - /* - * Version Descriptors, stored 2 byte values. - */ - uint8_t version1[2]; - uint8_t version2[2]; - uint8_t version3[2]; - uint8_t version4[2]; - uint8_t version5[2]; - uint8_t version6[2]; - uint8_t version7[2]; - uint8_t version8[2]; - - uint8_t reserved3[22]; - -#define SID_VENDOR_SPECIFIC_1_SIZE 160 - uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; -}; - -struct scsi_vpd_unit_serial_number -{ - uint8_t device; - uint8_t page_code; -#define SVPD_UNIT_SERIAL_NUMBER 0x80 - uint8_t reserved; - uint8_t length; /* serial number length */ -#define SVPD_SERIAL_NUM_SIZE 251 - uint8_t serial_num[SVPD_SERIAL_NUM_SIZE]; -}; - -struct scsi_read_capacity -{ - uint8_t opcode; - uint8_t byte2; - uint8_t addr[4]; - uint8_t unused[3]; - uint8_t control; -}; - -struct scsi_read_capacity_data -{ - uint8_t addr[4]; - uint8_t length[4]; -}; - -struct scsi_report_luns -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[3]; - uint8_t addr[4]; - uint8_t control; -}; - -struct scsi_report_luns_data { - uint8_t length[4]; /* length of LUN inventory, in bytes */ - uint8_t reserved[4]; /* unused */ - /* - * LUN inventory- we only support the type zero form for now. - */ - struct { - uint8_t lundata[8]; - } luns[1]; -}; -#define RPL_LUNDATA_ATYP_MASK 0xc0 /* MBZ for type 0 lun */ -#define RPL_LUNDATA_T0LUN 1 /* @ lundata[1] */ - - struct scsi_sense_data { uint8_t error_code; @@ -757,41 +117,6 @@ struct scsi_sense_data #define SSD_FULL_SIZE sizeof(struct scsi_sense_data) }; -struct scsi_mode_header_6 -{ - uint8_t data_length; /* Sense data length */ - uint8_t medium_type; - uint8_t dev_spec; - uint8_t blk_desc_len; -}; - -struct scsi_mode_header_10 -{ - uint8_t data_length[2];/* Sense data length */ - uint8_t medium_type; - uint8_t dev_spec; - uint8_t unused[2]; - uint8_t blk_desc_len[2]; -}; - -struct scsi_mode_page_header -{ - uint8_t page_code; - uint8_t page_length; -}; - -struct scsi_mode_blk_desc -{ - uint8_t density; - uint8_t nblocks[3]; - uint8_t reserved; - uint8_t blklen[3]; -}; - -#define SCSI_DEFAULT_DENSITY 0x00 /* use 'default' density */ -#define SCSI_SAME_DENSITY 0x7f /* use 'same' density- >= SCSI-2 only */ - - /* * Status Byte */ @@ -807,76 +132,7 @@ struct scsi_mode_blk_desc #define SCSI_STATUS_ACA_ACTIVE 0x30 #define SCSI_STATUS_TASK_ABORTED 0x40 -struct scsi_inquiry_pattern { - uint8_t type; - uint8_t media_type; -#define SIP_MEDIA_REMOVABLE 0x01 -#define SIP_MEDIA_FIXED 0x02 - const char *vendor; - const char *product; - const char *revision; -}; - -struct scsi_static_inquiry_pattern { - uint8_t type; - uint8_t media_type; - char vendor[SID_VENDOR_SIZE+1]; - char product[SID_PRODUCT_SIZE+1]; - char revision[SID_REVISION_SIZE+1]; -}; - -struct scsi_sense_quirk_entry { - struct scsi_inquiry_pattern inq_pat; - int num_sense_keys; - int num_ascs; - struct sense_key_table_entry *sense_key_info; - struct asc_table_entry *asc_info; -}; - -struct sense_key_table_entry { - uint8_t sense_key; - uint32_t action; - const char *desc; -}; - -struct asc_table_entry { - uint8_t asc; - uint8_t ascq; - uint32_t action; - const char *desc; -}; - -struct op_table_entry { - uint8_t opcode; - uint16_t opmask; - const char *desc; -}; - -struct scsi_op_quirk_entry { - struct scsi_inquiry_pattern inq_pat; - int num_ops; - struct op_table_entry *op_table; -}; - -typedef enum { - SSS_FLAG_NONE = 0x00, - SSS_FLAG_PRINT_COMMAND = 0x01 -} scsi_sense_string_flags; - -extern const char *scsi_sense_key_text[]; - /************************* Large Disk Handling ********************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static __inline int aic_sector_div(u_long capacity, int heads, int sectors); - -static __inline int -aic_sector_div(u_long capacity, int heads, int sectors) -{ - return (capacity / (heads * sectors)); -} -#else -static __inline int aic_sector_div(sector_t capacity, int heads, int sectors); - static __inline int aic_sector_div(sector_t capacity, int heads, int sectors) { @@ -884,7 +140,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors) sector_div(capacity, (heads * sectors)); return (int)capacity; } -#endif /**************************** Module Library Hack *****************************/ /* @@ -899,138 +154,15 @@ aic_sector_div(sector_t capacity, int heads, int sectors) #define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) #define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) -#define aic_sense_desc AIC_LIB_ENTRY(_sense_desc) -#define aic_sense_error_action AIC_LIB_ENTRY(_sense_error_action) -#define aic_error_action AIC_LIB_ENTRY(_error_action) -#define aic_op_desc AIC_LIB_ENTRY(_op_desc) -#define aic_cdb_string AIC_LIB_ENTRY(_cdb_string) -#define aic_print_inquiry AIC_LIB_ENTRY(_print_inquiry) #define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) -#define aic_calc_syncparam AIC_LIB_ENTRY(_calc_syncparam) -#define aic_calc_speed AIC_LIB_ENTRY(_calc_speed) -#define aic_inquiry_match AIC_LIB_ENTRY(_inquiry_match) -#define aic_static_inquiry_match AIC_LIB_ENTRY(_static_inquiry_match) -#define aic_parse_brace_option AIC_LIB_ENTRY(_parse_brace_option) - -/******************************************************************************/ - -void aic_sense_desc(int /*sense_key*/, int /*asc*/, - int /*ascq*/, struct scsi_inquiry_data*, - const char** /*sense_key_desc*/, - const char** /*asc_desc*/); -aic_sense_action aic_sense_error_action(struct scsi_sense_data*, - struct scsi_inquiry_data*, - uint32_t /*sense_flags*/); -uint32_t aic_error_action(struct scsi_cmnd *, - struct scsi_inquiry_data *, - cam_status, u_int); - -#define SF_RETRY_UA 0x01 -#define SF_NO_PRINT 0x02 -#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */ -#define SF_PRINT_ALWAYS 0x08 - - -const char * aic_op_desc(uint16_t /*opcode*/, struct scsi_inquiry_data*); -char * aic_cdb_string(uint8_t* /*cdb_ptr*/, char* /*cdb_string*/, - size_t /*len*/); -void aic_print_inquiry(struct scsi_inquiry_data*); u_int aic_calc_syncsrate(u_int /*period_factor*/); -u_int aic_calc_syncparam(u_int /*period*/); -u_int aic_calc_speed(u_int width, u_int period, u_int offset, - u_int min_rate); - -int aic_inquiry_match(caddr_t /*inqbuffer*/, - caddr_t /*table_entry*/); -int aic_static_inquiry_match(caddr_t /*inqbuffer*/, - caddr_t /*table_entry*/); typedef void aic_option_callback_t(u_long, int, int, int32_t); char * aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, aic_option_callback_t *, u_long); -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, - int *error_code, int *sense_key, - int *asc, int *ascq); -static __inline void scsi_ulto2b(uint32_t val, uint8_t *bytes); -static __inline void scsi_ulto3b(uint32_t val, uint8_t *bytes); -static __inline void scsi_ulto4b(uint32_t val, uint8_t *bytes); -static __inline uint32_t scsi_2btoul(uint8_t *bytes); -static __inline uint32_t scsi_3btoul(uint8_t *bytes); -static __inline int32_t scsi_3btol(uint8_t *bytes); -static __inline uint32_t scsi_4btoul(uint8_t *bytes); - -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, - int *error_code, int *sense_key, - int *asc, int *ascq) -{ - *error_code = sense->error_code & SSD_ERRCODE; - *sense_key = sense->flags & SSD_KEY; - *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; -} - -static __inline void -scsi_ulto2b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 8) & 0xff; - bytes[1] = val & 0xff; -} - -static __inline void -scsi_ulto3b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 16) & 0xff; - bytes[1] = (val >> 8) & 0xff; - bytes[2] = val & 0xff; -} - -static __inline void -scsi_ulto4b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 24) & 0xff; - bytes[1] = (val >> 16) & 0xff; - bytes[2] = (val >> 8) & 0xff; - bytes[3] = val & 0xff; -} - -static __inline uint32_t -scsi_2btoul(uint8_t *bytes) -{ - uint32_t rv; - - rv = (bytes[0] << 8) | - bytes[1]; - return (rv); -} - -static __inline uint32_t -scsi_3btoul(uint8_t *bytes) -{ - uint32_t rv; - - rv = (bytes[0] << 16) | - (bytes[1] << 8) | - bytes[2]; - return (rv); -} - -static __inline int32_t -scsi_3btol(uint8_t *bytes) -{ - uint32_t rc = scsi_3btoul(bytes); - - if (rc & 0x00800000) - rc |= 0xff000000; - - return (int32_t) rc; -} - static __inline uint32_t scsi_4btoul(uint8_t *bytes) { -- cgit v1.2.3 From e537a36d528053f6b9dbe6c88e763e835c0d3517 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 5 Jun 2005 02:07:14 -0500 Subject: [SCSI] use scatter lists for all block pc requests and simplify hw handlers Here's the proof of concept for this one. It converts scsi_wait_req to do correct REQ_BLOCK_PC submission (and works nicely in my setup). The final goal should be to eliminate struct scsi_request, but that can't be done until the character submission paths of sg and st are also modified. There's some loss of functionality to this: retries are no longer controllable (except by setting REQ_FASTFAIL) and the wait_req API needs to be altered, but it looks very nice. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 96 ++++++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7a91ca3d32a..253c1a98d15 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -232,23 +232,6 @@ void scsi_do_req(struct scsi_request *sreq, const void *cmnd, } EXPORT_SYMBOL(scsi_do_req); -static void scsi_wait_done(struct scsi_cmnd *cmd) -{ - struct request *req = cmd->request; - struct request_queue *q = cmd->device->request_queue; - unsigned long flags; - - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - - spin_lock_irqsave(q->queue_lock, flags); - if (blk_rq_tagged(req)) - blk_queue_end_tag(q, req); - spin_unlock_irqrestore(q->queue_lock, flags); - - if (req->waiting) - complete(req->waiting); -} - /* This is the end routine we get to if a command was never attached * to the request. Simply complete the request without changing * rq_status; this will cause a DRIVER_ERROR. */ @@ -263,19 +246,36 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); - - sreq->sr_request->waiting = &wait; - sreq->sr_request->rq_status = RQ_SCSI_BUSY; - sreq->sr_request->end_io = scsi_wait_req_end_io; - scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done, - timeout, retries); + struct request *req; + + if (bufflen) + req = blk_rq_map_kern(sreq->sr_device->request_queue, + sreq->sr_data_direction == DMA_TO_DEVICE, + buffer, bufflen, __GFP_WAIT); + else + req = blk_get_request(sreq->sr_device->request_queue, READ, + __GFP_WAIT); + req->flags |= REQ_NOMERGE; + req->waiting = &wait; + req->end_io = scsi_wait_req_end_io; + req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]); + req->sense = sreq->sr_sense_buffer; + req->sense_len = 0; + memcpy(req->cmd, cmnd, req->cmd_len); + req->timeout = timeout; + req->flags |= REQ_BLOCK_PC; + req->rq_disk = NULL; + blk_insert_request(sreq->sr_device->request_queue, req, + sreq->sr_data_direction == DMA_TO_DEVICE, NULL); wait_for_completion(&wait); sreq->sr_request->waiting = NULL; - if (sreq->sr_request->rq_status != RQ_SCSI_DONE) + sreq->sr_result = req->errors; + if (req->errors) sreq->sr_result |= (DRIVER_ERROR << 24); - __scsi_release_request(sreq); + blk_put_request(req); } + EXPORT_SYMBOL(scsi_wait_req); /* @@ -878,11 +878,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, return; } if (result) { - printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " - "= 0x%x\n", cmd->device->host->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, result); + if (!(req->flags & REQ_SPECIAL)) + printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " + "= 0x%x\n", cmd->device->host->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); @@ -1020,6 +1021,12 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, return -EOPNOTSUPP; } +static void scsi_generic_done(struct scsi_cmnd *cmd) +{ + BUG_ON(!blk_pc_request(cmd->request)); + scsi_io_completion(cmd, cmd->result == 0 ? cmd->bufflen : 0, 0); +} + static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; @@ -1061,7 +1068,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) * these two cases differently. We differentiate by looking * at request->cmd, as this tells us the real story. */ - if (req->flags & REQ_SPECIAL) { + if (req->flags & REQ_SPECIAL && req->special) { struct scsi_request *sreq = req->special; if (sreq->sr_magic == SCSI_REQ_MAGIC) { @@ -1073,7 +1080,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) cmd = req->special; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { - if(unlikely(specials_only)) { + if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) { if(specials_only == SDEV_QUIESCE || specials_only == SDEV_BLOCK) return BLKPREP_DEFER; @@ -1142,11 +1149,26 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) /* * Initialize the actual SCSI command for this request. */ - drv = *(struct scsi_driver **)req->rq_disk->private_data; - if (unlikely(!drv->init_command(cmd))) { - scsi_release_buffers(cmd); - scsi_put_command(cmd); - return BLKPREP_KILL; + if (req->rq_disk) { + drv = *(struct scsi_driver **)req->rq_disk->private_data; + if (unlikely(!drv->init_command(cmd))) { + scsi_release_buffers(cmd); + scsi_put_command(cmd); + return BLKPREP_KILL; + } + } else { + memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); + if (rq_data_dir(req) == WRITE) + cmd->sc_data_direction = DMA_TO_DEVICE; + else if (req->data_len) + cmd->sc_data_direction = DMA_FROM_DEVICE; + else + cmd->sc_data_direction = DMA_NONE; + + cmd->transfersize = req->data_len; + cmd->allowed = 3; + cmd->timeout_per_command = req->timeout; + cmd->done = scsi_generic_done; } } -- cgit v1.2.3 From 8e6401187ef7fb1edc2740832b48bf47ed2c90f2 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 15 Jun 2005 18:16:09 -0500 Subject: update scsi_wait_req to new format for blk_rq_map_kern() Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 253c1a98d15..60f07b6a5ff 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -246,15 +246,18 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); + int write = sreq->sr_data_direction == DMA_TO_DEVICE; struct request *req; - if (bufflen) - req = blk_rq_map_kern(sreq->sr_device->request_queue, - sreq->sr_data_direction == DMA_TO_DEVICE, - buffer, bufflen, __GFP_WAIT); - else - req = blk_get_request(sreq->sr_device->request_queue, READ, - __GFP_WAIT); + req = blk_get_request(sreq->sr_device->request_queue, write, + __GFP_WAIT); + if (bufflen && blk_rq_map_kern(sreq->sr_device->request_queue, req, + buffer, bufflen, __GFP_WAIT)) { + sreq->sr_result = DRIVER_ERROR << 24; + blk_put_request(req); + return; + } + req->flags |= REQ_NOMERGE; req->waiting = &wait; req->end_io = scsi_wait_req_end_io; -- cgit v1.2.3 From 392160335c798bbe94ab3aae6ea0c85d32b81bbc Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 15 Jun 2005 18:48:29 -0500 Subject: [SCSI] use scatter lists for all block pc requests and simplify hw handlers Original From: Mike Christie Add scsi_execute_req() as a replacement for scsi_wait_req() Fixed up various pieces (added REQ_SPECIAL and caught req use after free) Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 51 ++++++++++++++++++++- drivers/scsi/scsi_scan.c | 112 +++++++++++++++++++++-------------------------- 2 files changed, 99 insertions(+), 64 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 60f07b6a5ff..b8212c563fe 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -246,7 +246,7 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); - int write = sreq->sr_data_direction == DMA_TO_DEVICE; + int write = (sreq->sr_data_direction == DMA_TO_DEVICE); struct request *req; req = blk_get_request(sreq->sr_device->request_queue, write, @@ -281,6 +281,55 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, EXPORT_SYMBOL(scsi_wait_req); +/** + * scsi_execute_req - insert request and wait for the result + * @sdev: scsi device + * @cmd: scsi command + * @data_direction: data direction + * @buffer: data buffer + * @bufflen: len of buffer + * @sense: optional sense buffer + * @timeout: request timeout in seconds + * @retries: number of times to retry request + * + * scsi_execute_req returns the req->errors value which is the + * the scsi_cmnd result field. + **/ +int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries) +{ + struct request *req; + int write = (data_direction == DMA_TO_DEVICE); + int ret = DRIVER_ERROR << 24; + + req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); + + if (bufflen && blk_rq_map_kern(sdev->request_queue, req, + buffer, bufflen, __GFP_WAIT)) + goto out; + + req->cmd_len = COMMAND_SIZE(cmd[0]); + memcpy(req->cmd, cmd, req->cmd_len); + req->sense = sense; + req->sense_len = 0; + req->timeout = timeout; + req->flags |= REQ_BLOCK_PC | REQ_SPECIAL; + + /* + * head injection *required* here otherwise quiesce won't work + */ + blk_execute_rq(req->q, NULL, req, 1); + + ret = req->errors; + out: + blk_put_request(req); + + return ret; +} + +EXPORT_SYMBOL(scsi_execute_req); + /* * Function: scsi_init_cmd_errh() * diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 48edd67982a..d2ca4b8fbc1 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -111,15 +111,14 @@ MODULE_PARM_DESC(inq_timeout, /** * scsi_unlock_floptical - unlock device via a special MODE SENSE command - * @sreq: used to send the command + * @sdev: scsi device to send command to * @result: area to store the result of the MODE SENSE * * Description: - * Send a vendor specific MODE SENSE (not a MODE SELECT) command using - * @sreq to unlock a device, storing the (unused) results into result. + * Send a vendor specific MODE SENSE (not a MODE SELECT) command. * Called for BLIST_KEY devices. **/ -static void scsi_unlock_floptical(struct scsi_request *sreq, +static void scsi_unlock_floptical(struct scsi_device *sdev, unsigned char *result) { unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -129,11 +128,10 @@ static void scsi_unlock_floptical(struct scsi_request *sreq, scsi_cmd[1] = 0; scsi_cmd[2] = 0x2e; scsi_cmd[3] = 0; - scsi_cmd[4] = 0x2a; /* size */ + scsi_cmd[4] = 0x2a; /* size */ scsi_cmd[5] = 0; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; - scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3); + scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL, + SCSI_TIMEOUT, 3); } /** @@ -433,26 +431,26 @@ void scsi_target_reap(struct scsi_target *starget) /** * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY - * @sreq: used to send the INQUIRY + * @sdev: scsi_device to probe * @inq_result: area to store the INQUIRY result + * @result_len: len of inq_result * @bflags: store any bflags found here * * Description: - * Probe the lun associated with @sreq using a standard SCSI INQUIRY; + * Probe the lun associated with @req using a standard SCSI INQUIRY; * - * If the INQUIRY is successful, sreq->sr_result is zero and: the + * If the INQUIRY is successful, zero is returned and the * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length - * are copied to the Scsi_Device at @sreq->sr_device (sdev); - * any flags value is stored in *@bflags. + * are copied to the Scsi_Device any flags value is stored in *@bflags. **/ -static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, - int *bflags) +static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, + int result_len, int *bflags) { - struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ + char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; - int pass, count; + int pass, count, result; struct scsi_sense_hdr sshdr; *bflags = 0; @@ -475,28 +473,28 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; scsi_cmd[4] = (unsigned char) try_inquiry_len; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; + memset(sense, 0, sizeof(sense)); memset(inq_result, 0, try_inquiry_len); - scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result, - try_inquiry_len, - HZ/2 + HZ*scsi_inq_timeout, 3); + + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + inq_result, try_inquiry_len, sense, + HZ / 2 + HZ * scsi_inq_timeout, 3); SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " "with code 0x%x\n", - sreq->sr_result ? "failed" : "successful", - sreq->sr_result)); + result ? "failed" : "successful", result)); - if (sreq->sr_result) { + if (result) { /* * not-ready to ready transition [asc/ascq=0x28/0x0] * or power-on, reset [asc/ascq=0x29/0x0], continue. * INQUIRY should not yield UNIT_ATTENTION * but many buggy devices do so anyway. */ - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - scsi_request_normalize_sense(sreq, &sshdr)) { + if ((driver_byte(result) & DRIVER_SENSE) && + scsi_normalize_sense(sense, sizeof(sense), + &sshdr)) { if ((sshdr.sense_key == UNIT_ATTENTION) && ((sshdr.asc == 0x28) || (sshdr.asc == 0x29)) && @@ -507,7 +505,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, break; } - if (sreq->sr_result == 0) { + if (result == 0) { response_len = (unsigned char) inq_result[4] + 5; if (response_len > 255) response_len = first_inquiry_len; /* sanity */ @@ -556,8 +554,8 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, /* If the last transfer attempt got an error, assume the * peripheral doesn't exist or is dead. */ - if (sreq->sr_result) - return; + if (result) + return -EIO; /* Don't report any more data than the device says is valid */ sdev->inquiry_len = min(try_inquiry_len, response_len); @@ -593,7 +591,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) sdev->scsi_level++; - return; + return 0; } /** @@ -800,9 +798,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, void *hostdata) { struct scsi_device *sdev; - struct scsi_request *sreq; unsigned char *result; - int bflags, res = SCSI_SCAN_NO_RESPONSE; + int bflags, res = SCSI_SCAN_NO_RESPONSE, result_len = 256; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); /* @@ -831,16 +828,13 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, sdev = scsi_alloc_sdev(starget, lun, hostdata); if (!sdev) goto out; - sreq = scsi_allocate_request(sdev, GFP_ATOMIC); - if (!sreq) - goto out_free_sdev; - result = kmalloc(256, GFP_ATOMIC | + + result = kmalloc(result_len, GFP_ATOMIC | ((shost->unchecked_isa_dma) ? __GFP_DMA : 0)); if (!result) - goto out_free_sreq; + goto out_free_sdev; - scsi_probe_lun(sreq, result, &bflags); - if (sreq->sr_result) + if (scsi_probe_lun(sdev, result, result_len, &bflags)) goto out_free_result; /* @@ -868,7 +862,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (res == SCSI_SCAN_LUN_PRESENT) { if (bflags & BLIST_KEY) { sdev->lockable = 0; - scsi_unlock_floptical(sreq, result); + scsi_unlock_floptical(sdev, result); } if (bflagsp) *bflagsp = bflags; @@ -876,8 +870,6 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, out_free_result: kfree(result); - out_free_sreq: - scsi_release_request(sreq); out_free_sdev: if (res == SCSI_SCAN_LUN_PRESENT) { if (sdevp) { @@ -1065,13 +1057,14 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, int rescan) { char devname[64]; + char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned int length; unsigned int lun; unsigned int num_luns; unsigned int retries; + int result; struct scsi_lun *lunp, *lun_data; - struct scsi_request *sreq; u8 *data; struct scsi_sense_hdr sshdr; struct scsi_target *starget = scsi_target(sdev); @@ -1089,10 +1082,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, if (bflags & BLIST_NOLUN) return 0; - sreq = scsi_allocate_request(sdev, GFP_ATOMIC); - if (!sreq) - goto out; - sprintf(devname, "host %d channel %d id %d", sdev->host->host_no, sdev->channel, sdev->id); @@ -1110,7 +1099,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, lun_data = kmalloc(length, GFP_ATOMIC | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); if (!lun_data) - goto out_release_request; + goto out; scsi_cmd[0] = REPORT_LUNS; @@ -1129,8 +1118,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, scsi_cmd[10] = 0; /* reserved */ scsi_cmd[11] = 0; /* control */ - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; /* * We can get a UNIT ATTENTION, for example a power on/reset, so @@ -1146,29 +1133,30 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending" " REPORT LUNS to %s (try %d)\n", devname, retries)); - scsi_wait_req(sreq, scsi_cmd, lun_data, length, - SCSI_TIMEOUT + 4*HZ, 3); + + memset(sense, 0, sizeof(sense)); + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + lun_data, length, sense, + SCSI_TIMEOUT + 4 * HZ, 3); + SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" - " %s (try %d) result 0x%x\n", sreq->sr_result - ? "failed" : "successful", retries, - sreq->sr_result)); - if (sreq->sr_result == 0) + " %s (try %d) result 0x%x\n", result + ? "failed" : "successful", retries, result)); + if (result == 0) break; - else if (scsi_request_normalize_sense(sreq, &sshdr)) { + else if (scsi_normalize_sense(sense, sizeof(sense), &sshdr)) { if (sshdr.sense_key != UNIT_ATTENTION) break; } } - if (sreq->sr_result) { + if (result) { /* * The device probably does not support a REPORT LUN command */ kfree(lun_data); - scsi_release_request(sreq); return 1; } - scsi_release_request(sreq); /* * Get the length from the first four bytes of lun_data. @@ -1242,8 +1230,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, kfree(lun_data); return 0; - out_release_request: - scsi_release_request(sreq); out: /* * We are out of memory, don't try scanning any further. -- cgit v1.2.3 From 3b2946cc96bfafa90a555c70b2e876cbbd0fae98 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Mon, 15 Aug 2005 10:50:24 -0700 Subject: [SCSI] aacraid: Fix aacraid probe breakage (updated) This patch fixes the bad assumption of the aacraid driver with use_sg. I used the 3w-xxxx driver fix as a guide for this. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 79 +++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 26 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 8e349358729..83bfab73ff6 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -349,6 +349,27 @@ static void aac_io_done(struct scsi_cmnd * scsicmd) spin_unlock_irqrestore(host->host_lock, cpu_flags); } +static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len) +{ + void *buf; + unsigned int transfer_len; + struct scatterlist *sg = scsicmd->request_buffer; + + if (scsicmd->use_sg) { + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + transfer_len = min(sg->length, len + offset); + } else { + buf = scsicmd->request_buffer; + transfer_len = min(scsicmd->request_bufflen, len + offset); + } + + memcpy(buf + offset, data, transfer_len - offset); + + if (scsicmd->use_sg) + kunmap_atomic(buf - sg->offset, KM_IRQ0); + +} + static void get_container_name_callback(void *context, struct fib * fibptr) { struct aac_get_name_resp * get_name_reply; @@ -364,18 +385,22 @@ static void get_container_name_callback(void *context, struct fib * fibptr) /* Failure is irrelevant, using default value instead */ if ((le32_to_cpu(get_name_reply->status) == CT_OK) && (get_name_reply->data[0] != '\0')) { - int count; - char * dp; - char * sp = get_name_reply->data; + char *sp = get_name_reply->data; sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; while (*sp == ' ') ++sp; - count = sizeof(((struct inquiry_data *)NULL)->inqd_pid); - dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid; - if (*sp) do { - *dp++ = (*sp) ? *sp++ : ' '; - } while (--count > 0); + if (*sp) { + char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; + int count = sizeof(d); + char *dp = d; + do { + *dp++ = (*sp) ? *sp++ : ' '; + } while (--count > 0); + aac_internal_transfer(scsicmd, d, + offsetof(struct inquiry_data, inqd_pid), sizeof(d)); + } } + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; fib_complete(fibptr); @@ -1344,44 +1369,45 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) switch (scsicmd->cmnd[0]) { case INQUIRY: { - struct inquiry_data *inq_data_ptr; + struct inquiry_data inq_data; dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id)); - inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; - memset(inq_data_ptr, 0, sizeof (struct inquiry_data)); + memset(&inq_data, 0, sizeof (struct inquiry_data)); - inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ - inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ - inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ - inq_data_ptr->inqd_len = 31; + inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ + inq_data.inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ + inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ + inq_data.inqd_len = 31; /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ - inq_data_ptr->inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ + inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ /* * Set the Vendor, Product, and Revision Level * see: .c i.e. aac.c */ if (scsicmd->device->id == host->this_id) { - setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *))); - inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ + setinqstr(cardtype, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *))); + inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ + aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } - setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type); - inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + setinqstr(cardtype, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); + inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); return aac_get_container_name(scsicmd, cid); } case READ_CAPACITY: { u32 capacity; - char *cp; + char cp[8]; dprintk((KERN_DEBUG "READ CAPACITY command.\n")); if (fsa_dev_ptr[cid].size <= 0x100000000LL) capacity = fsa_dev_ptr[cid].size - 1; else capacity = (u32)-1; - cp = scsicmd->request_buffer; + cp[0] = (capacity >> 24) & 0xff; cp[1] = (capacity >> 16) & 0xff; cp[2] = (capacity >> 8) & 0xff; @@ -1390,6 +1416,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[5] = 0; cp[6] = 2; cp[7] = 0; + aac_internal_transfer(scsicmd, cp, 0, sizeof(cp)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -1399,15 +1426,15 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) case MODE_SENSE: { - char *mode_buf; + char mode_buf[4]; dprintk((KERN_DEBUG "MODE SENSE command.\n")); - mode_buf = scsicmd->request_buffer; mode_buf[0] = 3; /* Mode data length */ mode_buf[1] = 0; /* Medium type - default */ mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ mode_buf[3] = 0; /* Block descriptor length */ + aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -1415,10 +1442,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) } case MODE_SENSE_10: { - char *mode_buf; + char mode_buf[8]; dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); - mode_buf = scsicmd->request_buffer; mode_buf[0] = 0; /* Mode data length (MSB) */ mode_buf[1] = 6; /* Mode data length (LSB) */ mode_buf[2] = 0; /* Medium type - default */ @@ -1427,6 +1453,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[5] = 0; /* reserved */ mode_buf[6] = 0; /* Block descriptor length (MSB) */ mode_buf[7] = 0; /* Block descriptor length (LSB) */ + aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); -- cgit v1.2.3 From be042f240a8528b8f6b741a484cdbbf515698388 Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 15 Aug 2005 16:52:58 -0500 Subject: [SCSI] ibmvscsi eh locking With the removal of the spinlocking around eh calls, we need to add a little more locking back in, otherwise we do some naked list manipulation. Signed-off-by: Dave Boutcher Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index fe09d145542..1ae800ae93d 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -826,11 +826,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) struct srp_event_struct *tmp_evt, *found_evt; union viosrp_iu srp_rsp; int rsp_rc; + unsigned long flags; u16 lun = lun_from_dev(cmd->device); /* First, find this command in our sent list so we can figure * out the correct tag */ + spin_lock_irqsave(hostdata->host->host_lock, flags); found_evt = NULL; list_for_each_entry(tmp_evt, &hostdata->sent, list) { if (tmp_evt->cmnd == cmd) { @@ -839,11 +841,14 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) } } - if (!found_evt) + if (!found_evt) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return FAILED; + } evt = get_event_struct(&hostdata->pool); if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n"); return FAILED; } @@ -867,7 +872,9 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); return FAILED; } @@ -901,6 +908,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) * The event is no longer in our list. Make sure it didn't * complete while we were aborting */ + spin_lock_irqsave(hostdata->host->host_lock, flags); found_evt = NULL; list_for_each_entry(tmp_evt, &hostdata->sent, list) { if (tmp_evt->cmnd == cmd) { @@ -910,6 +918,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) } if (found_evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_INFO "ibmvscsi: aborted task tag 0x%lx completed\n", tsk_mgmt->managed_task_tag); @@ -924,6 +933,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) list_del(&found_evt->list); unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); atomic_inc(&hostdata->request_limit); return SUCCESS; } @@ -943,10 +953,13 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) struct srp_event_struct *tmp_evt, *pos; union viosrp_iu srp_rsp; int rsp_rc; + unsigned long flags; u16 lun = lun_from_dev(cmd->device); + spin_lock_irqsave(hostdata->host->host_lock, flags); evt = get_event_struct(&hostdata->pool); if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n"); return FAILED; } @@ -969,7 +982,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); return FAILED; } @@ -1002,6 +1017,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) /* We need to find all commands for this LUN that have not yet been * responded to, and fail them with DID_RESET */ + spin_lock_irqsave(hostdata->host->host_lock, flags); list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { if (tmp_evt->cmnd) @@ -1017,6 +1033,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) tmp_evt->done(tmp_evt); } } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return SUCCESS; } -- cgit v1.2.3 From de540a53f2f7b68a48c3021e5ab78ea49f6cf21c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 20 Aug 2005 21:27:27 +0200 Subject: [SCSI] drivers/scsi/constants.c should include scsi_dbg.h C files should include the files with the prototypes for their global functions. Signed-off-by: Adrian Bunk Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index ec161733a82..0d58d3538bd 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -17,6 +17,7 @@ #include #include #include +#include -- cgit v1.2.3 From 8224bfa84d510630b40ea460b2bb380c91acb8ae Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 22 Aug 2005 14:38:26 -0500 Subject: [SCSI] ibmvscsi timeout fix This patch fixes a long term borkenness in ibmvscsi where we were using the wrong timeout field from the scsi command (and using the wrong units.) Now broken by the fact that the scsi_cmnd timeout field is gone entirely. This only worked before because all the SCSI targets assumed that 0 was default. Signed-off-by: Dave Boutcher Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 1ae800ae93d..e3e6752c410 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -594,7 +594,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, init_event_struct(evt_struct, handle_cmd_rsp, VIOSRP_SRP_FORMAT, - cmnd->timeout); + cmnd->timeout_per_command/HZ); evt_struct->cmnd = cmnd; evt_struct->cmnd_done = done; -- cgit v1.2.3 From 51490c89f95b8581782e9baa855da166441852be Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 5 Jul 2005 18:18:08 -0700 Subject: [SCSI] sr.c: Fix getting wrong size Here's the problem. Try to do this on 2.6.12: - Kill udev and HAL - Insert a CD-ROM into a SCSI or USB CD-ROM drive - Run dd if=/dev/scd0 - cat /sys/block/sr0/size - Eject the CD, insert a different one - Run dd if=/dev/scd0 This is likely to do "access beyond the end of device", if you let it - cat /sys/block/sr0/size This shows the size of a previous CD, even though dd was supposed to revalidate the device. - Run dd if=/dev/scd0 The second run of dd works correctly! The bug was introduced in 2.5.31, when Al fixes the recursive opens in partitioning. Before, the code worked like this: - Block layer called cdrom_open directly - cdrom_open called sr_open - sr_open called check_disk_change - check_disk_change called sr_media_change - sr_media_change did cd->needs_disk_change=1 - before returning sr_open tested cd->needs_disk_change and called get_sector_size. In 2.6.12, the check_disk_change is called from cdrom_open only. Thus: - Block layer calls sr_bd_open - sr_bd_open calls cdrom_open - cdrom_open calls sr_open - sr_open tests cd->needs_disk_change, which wasn't set yet; returns - cdrom_open calls check_disk_change - check_disk_change calls sr_media_change - sr_media_change does cd->needs_disk_change=1, but nobody cares Acked by: Alexander Viro Signed-off-by: James Bottomley --- drivers/scsi/sr.c | 24 ++---------------------- drivers/scsi/sr.h | 1 - 2 files changed, 2 insertions(+), 23 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2f259f24952..f63d8c6c2a3 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -199,15 +199,7 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot) /* check multisession offset etc */ sr_cd_check(cdi); - /* - * If the disk changed, the capacity will now be different, - * so we force a re-read of this information - * Force 2048 for the sector size so that filesystems won't - * be trying to use something that is too small if the disc - * has changed. - */ - cd->needs_sector_size = 1; - cd->device->sector_size = 2048; + get_sectorsize(cd); } return retval; } @@ -538,13 +530,6 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) if (!scsi_block_when_processing_errors(sdev)) goto error_out; - /* - * If this device did not have media in the drive at boot time, then - * we would have been unable to get the sector size. Check to see if - * this is the case, and try again. - */ - if (cd->needs_sector_size) - get_sectorsize(cd); return 0; error_out: @@ -604,7 +589,6 @@ static int sr_probe(struct device *dev) cd->driver = &sr_template; cd->disk = disk; cd->capacity = 0x1fffff; - cd->needs_sector_size = 1; cd->device->changed = 1; /* force recheck CD type */ cd->use = 1; cd->readcd_known = 0; @@ -694,7 +678,6 @@ static void get_sectorsize(struct scsi_cd *cd) if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ - cd->needs_sector_size = 1; } else { #if 0 if (cdrom_get_last_written(&cd->cdi, @@ -727,7 +710,6 @@ static void get_sectorsize(struct scsi_cd *cd) printk("%s: unsupported sector size %d.\n", cd->cdi.name, sector_size); cd->capacity = 0; - cd->needs_sector_size = 1; } cd->device->sector_size = sector_size; @@ -736,7 +718,6 @@ static void get_sectorsize(struct scsi_cd *cd) * Add this so that we have the ability to correctly gauge * what the device is capable of. */ - cd->needs_sector_size = 0; set_capacity(cd->disk, cd->capacity); } @@ -748,8 +729,7 @@ out: Enomem: cd->capacity = 0x1fffff; - sector_size = 2048; /* A guess, just in case */ - cd->needs_sector_size = 1; + cd->device->sector_size = 2048; /* A guess, just in case */ if (SRpnt) scsi_release_request(SRpnt); goto out; diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 0b317800720..d2bcd99c272 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -33,7 +33,6 @@ typedef struct scsi_cd { struct scsi_device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned needs_sector_size:1; /* needs to get sector size */ unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ -- cgit v1.2.3 From 1cf72699c1530c3e4ac3d58344f6a6a40a2f46d3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:27:01 -0500 Subject: [SCSI] convert the remaining mid-layer pieces to scsi_execute_req After this, we just have some drivers, all the ULDs and the SPI transport class using scsi_wait_req(). Signed-off-by: James Bottomley --- drivers/scsi/scsi_ioctl.c | 46 ++++++++--------------- drivers/scsi/scsi_lib.c | 94 +++++++++++++++++------------------------------ drivers/scsi/sd.c | 5 ++- drivers/scsi/sr.c | 2 +- 4 files changed, 53 insertions(+), 94 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index f5bf5c07be9..5f399c9c68e 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -88,25 +88,21 @@ static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { - struct scsi_request *sreq; int result; struct scsi_sense_hdr sshdr; + char sense[SCSI_SENSE_BUFFERSIZE]; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) { - printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n"); - return -ENOMEM; - } - sreq->sr_data_direction = DMA_NONE; - scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + memset(sense, 0, sizeof(*sense)); + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, + sense, timeout, retries); - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - (scsi_request_normalize_sense(sreq, &sshdr))) { + if ((driver_byte(result) & DRIVER_SENSE) && + (scsi_normalize_sense(sense, sizeof(*sense), &sshdr))) { switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) @@ -125,7 +121,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; - sreq->sr_result = 0; /* This is no longer considered an error */ + result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ @@ -135,15 +131,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sdev->channel, sdev->id, sdev->lun, - sreq->sr_result); - scsi_print_req_sense(" ", sreq); + result); + __scsi_print_sense(" ", sense, sizeof(*sense)); break; } } - result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - scsi_release_request(sreq); return result; } @@ -208,8 +202,8 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; char __user *cmd_in; - struct scsi_request *sreq; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; @@ -321,31 +315,23 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, break; } - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) { - result = -EINTR; - goto error; - } - - sreq->sr_data_direction = data_direction; - scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); - + result = scsi_execute_req(sdev, cmd, data_direction, buf, needed, + sense, timeout, retries); + /* * If there was an error condition, pass the info back to the user. */ - result = sreq->sr_result; if (result) { - int sb_len = sizeof(sreq->sr_sense_buffer); + int sb_len = sizeof(*sense); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; - if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) + if (copy_to_user(cmd_in, sense, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } - scsi_release_request(sreq); error: kfree(buf); return result; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 278e0c99b2a..3f3accd6cd4 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1615,7 +1615,7 @@ void scsi_exit_queue(void) /** * __scsi_mode_sense - issue a mode sense, falling back from 10 to * six bytes if necessary. - * @sreq: SCSI request to fill in with the MODE_SENSE + * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned * @modepage: mode page being requested * @buffer: request buffer (may not be smaller than eight bytes) @@ -1623,26 +1623,38 @@ void scsi_exit_queue(void) * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data + * @sense: place to put sense data (or NULL if no sense to be collected). + * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if unsuccessful, or the header offset (either 4 * or 8 depending on whether a six or ten byte command was * issued) if successful. **/ int -__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, +scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data) { + struct scsi_mode_data *data, char *sense) { unsigned char cmd[12]; int use_10_for_ms; int header_length; + int result; + char *sense_buffer = NULL; memset(data, 0, sizeof(*data)); memset(&cmd[0], 0, 12); cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; + if (!sense) { + sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!sense_buffer) { + dev_printk(KERN_ERR, &sdev->sdev_gendev, "failed to allocate sense buffer\n"); + return 0; + } + sense = sense_buffer; + } retry: - use_10_for_ms = sreq->sr_device->use_10_for_ms; + use_10_for_ms = sdev->use_10_for_ms; if (use_10_for_ms) { if (len < 8) @@ -1660,36 +1672,35 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, header_length = 4; } - sreq->sr_cmd_len = 0; - memset(sreq->sr_sense_buffer, 0, sizeof(sreq->sr_sense_buffer)); - sreq->sr_data_direction = DMA_FROM_DEVICE; + memset(sense, 0, SCSI_SENSE_BUFFERSIZE); memset(buffer, 0, len); - scsi_wait_req(sreq, cmd, buffer, len, timeout, retries); + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, + sense, timeout, retries); /* This code looks awful: what it's doing is making sure an * ILLEGAL REQUEST sense return identifies the actual command * byte as the problem. MODE_SENSE commands can return * ILLEGAL REQUEST if the code page isn't supported */ - if (use_10_for_ms && !scsi_status_is_good(sreq->sr_result) && - (driver_byte(sreq->sr_result) & DRIVER_SENSE)) { + if (use_10_for_ms && !scsi_status_is_good(result) && + (driver_byte(result) & DRIVER_SENSE)) { struct scsi_sense_hdr sshdr; - if (scsi_request_normalize_sense(sreq, &sshdr)) { + if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { if ((sshdr.sense_key == ILLEGAL_REQUEST) && (sshdr.asc == 0x20) && (sshdr.ascq == 0)) { /* * Invalid command operation code */ - sreq->sr_device->use_10_for_ms = 0; + sdev->use_10_for_ms = 0; goto retry; } } } - if(scsi_status_is_good(sreq->sr_result)) { + if(scsi_status_is_good(result)) { data->header_length = header_length; if(use_10_for_ms) { data->length = buffer[0]*256 + buffer[1] + 2; @@ -1706,73 +1717,34 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, } } - return sreq->sr_result; -} -EXPORT_SYMBOL(__scsi_mode_sense); - -/** - * scsi_mode_sense - issue a mode sense, falling back from 10 to - * six bytes if necessary. - * @sdev: scsi device to send command to. - * @dbd: set if mode sense will disable block descriptors in the return - * @modepage: mode page being requested - * @buffer: request buffer (may not be smaller than eight bytes) - * @len: length of request buffer. - * @timeout: command timeout - * @retries: number of retries before failing - * - * Returns zero if unsuccessful, or the header offset (either 4 - * or 8 depending on whether a six or ten byte command was - * issued) if successful. - **/ -int -scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, - unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data) -{ - struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); - int ret; - - if (!sreq) - return -1; - - ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len, - timeout, retries, data); - - scsi_release_request(sreq); - - return ret; + kfree(sense_buffer); + return result; } EXPORT_SYMBOL(scsi_mode_sense); int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) { - struct scsi_request *sreq; char cmd[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0, }; + char sense[SCSI_SENSE_BUFFERSIZE]; int result; - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) - return -ENOMEM; - - sreq->sr_data_direction = DMA_NONE; - scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sense, + timeout, retries); - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) { + if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { struct scsi_sense_hdr sshdr; - if ((scsi_request_normalize_sense(sreq, &sshdr)) && + if ((scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, + &sshdr)) && ((sshdr.sense_key == UNIT_ATTENTION) || (sshdr.sense_key == NOT_READY))) { sdev->changed = 1; - sreq->sr_result = 0; + result = 0; } } - result = sreq->sr_result; - scsi_release_request(sreq); return result; } EXPORT_SYMBOL(scsi_test_unit_ready); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0410e1bf109..15c2039059c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1299,8 +1299,9 @@ static inline int sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, unsigned char *buffer, int len, struct scsi_mode_data *data) { - return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len, - SD_TIMEOUT, SD_MAX_RETRIES, data); + return scsi_mode_sense(SRpnt->sr_device, dbd, modepage, buffer, len, + SD_TIMEOUT, SD_MAX_RETRIES, data, + SRpnt->sr_sense_buffer); } /* diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2f259f24952..8cbe6e00418 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -817,7 +817,7 @@ static void get_capabilities(struct scsi_cd *cd) /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, - SR_TIMEOUT, 3, &data); + SR_TIMEOUT, 3, &data, NULL); if (!scsi_status_is_good(rc)) { /* failed, drive doesn't have capabilities mode page */ -- cgit v1.2.3 From 33aa687db90dd8541bd5e9a762eebf880eaee767 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:31:14 -0500 Subject: [SCSI] convert SPI transport class to scsi_execute This one's slightly more difficult. The transport class uses REQ_FAILFAST, so another interface (scsi_execute) had to be invented to take the extra flag. Also, the sense functions are shifted around to allow spi_execute to place data directly into a struct scsi_sense_hdr. With this change, there's probably a lot of unnecessary sense buffer allocation going on which we can fix later. Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 6 +- drivers/scsi/scsi_lib.c | 13 ++-- drivers/scsi/scsi_transport_spi.c | 124 ++++++++++++++++++-------------------- 3 files changed, 69 insertions(+), 74 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e9c451ba71f..2686d5672e5 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1847,12 +1847,16 @@ EXPORT_SYMBOL(scsi_reset_provider); int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr) { - if (!sense_buffer || !sb_len || (sense_buffer[0] & 0x70) != 0x70) + if (!sense_buffer || !sb_len) return 0; memset(sshdr, 0, sizeof(struct scsi_sense_hdr)); sshdr->response_code = (sense_buffer[0] & 0x7f); + + if (!scsi_sense_valid(sshdr)) + return 0; + if (sshdr->response_code >= 0x72) { /* * descriptor format diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3f3accd6cd4..42edf29223a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -282,7 +282,7 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, EXPORT_SYMBOL(scsi_wait_req); /** - * scsi_execute_req - insert request and wait for the result + * scsi_execute - insert request and wait for the result * @sdev: scsi device * @cmd: scsi command * @data_direction: data direction @@ -291,13 +291,14 @@ EXPORT_SYMBOL(scsi_wait_req); * @sense: optional sense buffer * @timeout: request timeout in seconds * @retries: number of times to retry request + * @flags: or into request flags; * * scsi_execute_req returns the req->errors value which is the * the scsi_cmnd result field. **/ -int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries) +int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries, int flags) { struct request *req; int write = (data_direction == DMA_TO_DEVICE); @@ -314,7 +315,7 @@ int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, req->sense = sense; req->sense_len = 0; req->timeout = timeout; - req->flags |= REQ_BLOCK_PC | REQ_SPECIAL; + req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL; /* * head injection *required* here otherwise quiesce won't work @@ -328,7 +329,7 @@ int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, return ret; } -EXPORT_SYMBOL(scsi_execute_req); +EXPORT_SYMBOL(scsi_execute); /* * Function: scsi_init_cmd_errh() diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 89f6b7feb9c..874042f1899 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -28,7 +28,7 @@ #include "scsi_priv.h" #include #include -#include +#include #include #include #include @@ -108,25 +108,33 @@ static int sprint_frac(char *dest, int value, int denom) /* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions * resulting from (likely) bus and device resets */ -static void spi_wait_req(struct scsi_request *sreq, const void *cmd, - void *buffer, unsigned bufflen) +static int spi_execute(struct scsi_device *sdev, const void *cmd, + enum dma_data_direction dir, + void *buffer, unsigned bufflen, + struct scsi_sense_hdr *sshdr) { - int i; + int i, result; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; for(i = 0; i < DV_RETRIES; i++) { - sreq->sr_request->flags |= REQ_FAILFAST; - - scsi_wait_req(sreq, cmd, buffer, bufflen, - DV_TIMEOUT, /* retries */ 1); - if (sreq->sr_result & DRIVER_SENSE) { - struct scsi_sense_hdr sshdr; - if (scsi_request_normalize_sense(sreq, &sshdr) - && sshdr.sense_key == UNIT_ATTENTION) + /* FIXME: need to set REQ_FAILFAST */ + result = scsi_execute(sdev, cmd, dir, buffer, bufflen, + sense, DV_TIMEOUT, /* retries */ 1, + REQ_FAILFAST); + if (result & DRIVER_SENSE) { + struct scsi_sense_hdr sshdr_tmp; + if (!sshdr) + sshdr = &sshdr_tmp; + + if (scsi_normalize_sense(sense, sizeof(*sense), + sshdr) + && sshdr->sense_key == UNIT_ATTENTION) continue; } break; } + return result; } static struct { @@ -546,13 +554,13 @@ enum spi_compare_returns { /* This is for read/write Domain Validation: If the device supports * an echo buffer, we do read/write tests to it */ static enum spi_compare_returns -spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, +spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer, u8 *ptr, const int retries) { - struct scsi_device *sdev = sreq->sr_device; int len = ptr - buffer; - int j, k, r; + int j, k, r, result; unsigned int pattern = 0x0000ffff; + struct scsi_sense_hdr sshdr; const char spi_write_buffer[] = { WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 @@ -597,14 +605,12 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, } for (r = 0; r < retries; r++) { - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_TO_DEVICE; - spi_wait_req(sreq, spi_write_buffer, buffer, len); - if(sreq->sr_result || !scsi_device_online(sdev)) { - struct scsi_sense_hdr sshdr; + result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE, + buffer, len, &sshdr); + if(result || !scsi_device_online(sdev)) { scsi_device_set_state(sdev, SDEV_QUIESCE); - if (scsi_request_normalize_sense(sreq, &sshdr) + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST /* INVALID FIELD IN CDB */ && sshdr.asc == 0x24 && sshdr.ascq == 0x00) @@ -616,14 +622,13 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, return SPI_COMPARE_SKIP_TEST; - SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result); + SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", result); return SPI_COMPARE_FAILURE; } memset(ptr, 0, len); - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_FROM_DEVICE; - spi_wait_req(sreq, spi_read_buffer, ptr, len); + spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE, + ptr, len, NULL); scsi_device_set_state(sdev, SDEV_QUIESCE); if (memcmp(buffer, ptr, len) != 0) @@ -635,25 +640,22 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, /* This is for the simplest form of Domain Validation: a read test * on the inquiry data from the device */ static enum spi_compare_returns -spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, +spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer, u8 *ptr, const int retries) { - int r; - const int len = sreq->sr_device->inquiry_len; - struct scsi_device *sdev = sreq->sr_device; + int r, result; + const int len = sdev->inquiry_len; const char spi_inquiry[] = { INQUIRY, 0, 0, 0, len, 0 }; for (r = 0; r < retries; r++) { - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_FROM_DEVICE; - memset(ptr, 0, len); - spi_wait_req(sreq, spi_inquiry, ptr, len); + result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE, + ptr, len, NULL); - if(sreq->sr_result || !scsi_device_online(sdev)) { + if(result || !scsi_device_online(sdev)) { scsi_device_set_state(sdev, SDEV_QUIESCE); return SPI_COMPARE_FAILURE; } @@ -674,12 +676,11 @@ spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, } static enum spi_compare_returns -spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, +spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr, enum spi_compare_returns - (*compare_fn)(struct scsi_request *, u8 *, u8 *, int)) + (*compare_fn)(struct scsi_device *, u8 *, u8 *, int)) { - struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); - struct scsi_device *sdev = sreq->sr_device; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); struct scsi_target *starget = sdev->sdev_target; int period = 0, prevperiod = 0; enum spi_compare_returns retval; @@ -687,7 +688,7 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, for (;;) { int newperiod; - retval = compare_fn(sreq, buffer, ptr, DV_LOOPS); + retval = compare_fn(sdev, buffer, ptr, DV_LOOPS); if (retval == SPI_COMPARE_SUCCESS || retval == SPI_COMPARE_SKIP_TEST) @@ -733,9 +734,9 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, } static int -spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) +spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) { - int l; + int l, result; /* first off do a test unit ready. This can error out * because of reservations or some other reason. If it @@ -751,18 +752,16 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) }; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_NONE; - /* We send a set of three TURs to clear any outstanding * unit attention conditions if they exist (Otherwise the * buffer tests won't be happy). If the TUR still fails * (reservation conflict, device not ready, etc) just * skip the write tests */ for (l = 0; ; l++) { - spi_wait_req(sreq, spi_test_unit_ready, NULL, 0); + result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE, + NULL, 0, NULL); - if(sreq->sr_result) { + if(result) { if(l >= 3) return 0; } else { @@ -771,12 +770,10 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) } } - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; + result = spi_execute(sdev, spi_read_buffer_descriptor, + DMA_FROM_DEVICE, buffer, 4, NULL); - spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4); - - if (sreq->sr_result) + if (result) /* Device has no echo buffer */ return 0; @@ -784,17 +781,16 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) } static void -spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) +spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) { - struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); - struct scsi_device *sdev = sreq->sr_device; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); struct scsi_target *starget = sdev->sdev_target; int len = sdev->inquiry_len; /* first set us up for narrow async */ DV_SET(offset, 0); DV_SET(width, 0); - if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS) + if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS) != SPI_COMPARE_SUCCESS) { SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); /* FIXME: should probably offline the device here? */ @@ -806,7 +802,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) scsi_device_wide(sdev)) { i->f->set_width(starget, 1); - if (spi_dv_device_compare_inquiry(sreq, buffer, + if (spi_dv_device_compare_inquiry(sdev, buffer, buffer + len, DV_LOOPS) != SPI_COMPARE_SUCCESS) { @@ -827,7 +823,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) len = 0; if (scsi_device_dt(sdev)) - len = spi_dv_device_get_echo_buffer(sreq, buffer); + len = spi_dv_device_get_echo_buffer(sdev, buffer); retry: @@ -853,7 +849,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) if (len == 0) { SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n"); - spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_retrain(sdev, buffer, buffer + len, spi_dv_device_compare_inquiry); return; } @@ -863,7 +859,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) len = SPI_MAX_ECHO_BUFFER_SIZE; } - if (spi_dv_retrain(sreq, buffer, buffer + len, + if (spi_dv_retrain(sdev, buffer, buffer + len, spi_dv_device_echo_buffer) == SPI_COMPARE_SKIP_TEST) { /* OK, the stupid drive can't do a write echo buffer @@ -886,16 +882,12 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) void spi_dv_device(struct scsi_device *sdev) { - struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); struct scsi_target *starget = sdev->sdev_target; u8 *buffer; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; - if (unlikely(!sreq)) - return; - if (unlikely(scsi_device_get(sdev))) - goto out_free_req; + return; buffer = kmalloc(len, GFP_KERNEL); @@ -916,7 +908,7 @@ spi_dv_device(struct scsi_device *sdev) SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n"); - spi_dv_device_internal(sreq, buffer); + spi_dv_device_internal(sdev, buffer); SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n"); @@ -931,8 +923,6 @@ spi_dv_device(struct scsi_device *sdev) kfree(buffer); out_put: scsi_device_put(sdev); - out_free_req: - scsi_release_request(sreq); } EXPORT_SYMBOL(spi_dv_device); -- cgit v1.2.3 From ea73a9f23906c374b697cd5b0d64f6dceced63de Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:33:52 -0500 Subject: [SCSI] convert sd to scsi_execute_req (and update the scsi_execute_req API) This one removes struct scsi_request entirely from sd. In the process, I noticed we have no callers of scsi_wait_req who don't immediately normalise the sense, so I updated the API to make it take a struct scsi_sense_hdr instead of simply a big sense buffer. Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 48 +++++++------- drivers/scsi/scsi_ioctl.c | 15 ++--- drivers/scsi/scsi_lib.c | 67 +++++++++++-------- drivers/scsi/scsi_scan.c | 13 ++-- drivers/scsi/sd.c | 160 +++++++++++++++++++--------------------------- 5 files changed, 139 insertions(+), 164 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 0d58d3538bd..f6be2c1c394 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1156,6 +1156,31 @@ scsi_show_extd_sense(unsigned char asc, unsigned char ascq) } } +void +scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) +{ + const char *sense_txt; + /* An example of deferred is when an earlier write to disk cache + * succeeded, but now the disk discovers that it cannot write the + * data to the magnetic media. + */ + const char *error = scsi_sense_is_deferred(sshdr) ? + "<>" : "Current"; + printk(KERN_INFO "%s: %s", name, error); + if (sshdr->response_code >= 0x72) + printk(" [descriptor]"); + + sense_txt = scsi_sense_key_string(sshdr->sense_key); + if (sense_txt) + printk(": sense key: %s\n", sense_txt); + else + printk(": sense key=0x%x\n", sshdr->sense_key); + printk(KERN_INFO " "); + scsi_show_extd_sense(sshdr->asc, sshdr->ascq); + printk("\n"); +} +EXPORT_SYMBOL(scsi_print_sense_hdr); + /* Print sense information */ void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, @@ -1163,8 +1188,6 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer, { int k, num, res; unsigned int info; - const char *error; - const char *sense_txt; struct scsi_sense_hdr ssh; res = scsi_normalize_sense(sense_buffer, sense_len, &ssh); @@ -1182,26 +1205,7 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer, printk("\n"); return; } - - /* An example of deferred is when an earlier write to disk cache - * succeeded, but now the disk discovers that it cannot write the - * data to the magnetic media. - */ - error = scsi_sense_is_deferred(&ssh) ? - "<>" : "Current"; - printk(KERN_INFO "%s: %s", name, error); - if (ssh.response_code >= 0x72) - printk(" [descriptor]"); - - sense_txt = scsi_sense_key_string(ssh.sense_key); - if (sense_txt) - printk(": sense key: %s\n", sense_txt); - else - printk(": sense key=0x%x\n", ssh.sense_key); - printk(KERN_INFO " "); - scsi_show_extd_sense(ssh.asc, ssh.ascq); - printk("\n"); - + scsi_print_sense_hdr(name, &ssh); if (ssh.response_code < 0x72) { /* only decode extras for "fixed" format now */ char buff[80]; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 5f399c9c68e..179a767d221 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -90,19 +90,16 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, { int result; struct scsi_sense_hdr sshdr; - char sense[SCSI_SENSE_BUFFERSIZE]; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - - memset(sense, 0, sizeof(*sense)); result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, - sense, timeout, retries); + &sshdr, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); if ((driver_byte(result) & DRIVER_SENSE) && - (scsi_normalize_sense(sense, sizeof(*sense), &sshdr))) { + (scsi_sense_valid(&sshdr))) { switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) @@ -132,7 +129,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sdev->id, sdev->lun, result); - __scsi_print_sense(" ", sense, sizeof(*sense)); + scsi_print_sense_hdr(" ", &sshdr); break; } } @@ -315,9 +312,9 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, break; } - result = scsi_execute_req(sdev, cmd, data_direction, buf, needed, - sense, timeout, retries); - + result = scsi_execute(sdev, cmd, data_direction, buf, needed, + sense, timeout, retries, 0); + /* * If there was an error condition, pass the info back to the user. */ diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 42edf29223a..bdea26b56dc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -293,8 +293,8 @@ EXPORT_SYMBOL(scsi_wait_req); * @retries: number of times to retry request * @flags: or into request flags; * - * scsi_execute_req returns the req->errors value which is the - * the scsi_cmnd result field. + * returns the req->errors value which is the the scsi_cmnd result + * field. **/ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, @@ -328,9 +328,31 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, return ret; } - EXPORT_SYMBOL(scsi_execute); + +int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + struct scsi_sense_hdr *sshdr, int timeout, int retries) +{ + char *sense = NULL; + + if (sshdr) { + sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!sense) + return DRIVER_ERROR << 24; + memset(sense, 0, sizeof(*sense)); + } + int result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, + sense, timeout, retries, 0); + if (sshdr) + scsi_normalize_sense(sense, sizeof(*sense), sshdr); + + kfree(sense); + return result; +} +EXPORT_SYMBOL(scsi_execute_req); + /* * Function: scsi_init_cmd_errh() * @@ -1614,7 +1636,7 @@ void scsi_exit_queue(void) } } /** - * __scsi_mode_sense - issue a mode sense, falling back from 10 to + * scsi_mode_sense - issue a mode sense, falling back from 10 to * six bytes if necessary. * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned @@ -1634,26 +1656,22 @@ void scsi_exit_queue(void) int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data, char *sense) { + struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { unsigned char cmd[12]; int use_10_for_ms; int header_length; int result; - char *sense_buffer = NULL; + struct scsi_sense_hdr my_sshdr; memset(data, 0, sizeof(*data)); memset(&cmd[0], 0, 12); cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; - if (!sense) { - sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - if (!sense_buffer) { - dev_printk(KERN_ERR, &sdev->sdev_gendev, "failed to allocate sense buffer\n"); - return 0; - } - sense = sense_buffer; - } + /* caller might not be interested in sense, but we need it */ + if (!sshdr) + sshdr = &my_sshdr; + retry: use_10_for_ms = sdev->use_10_for_ms; @@ -1673,12 +1691,10 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, header_length = 4; } - memset(sense, 0, SCSI_SENSE_BUFFERSIZE); - memset(buffer, 0, len); result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, - sense, timeout, retries); + sshdr, timeout, retries); /* This code looks awful: what it's doing is making sure an * ILLEGAL REQUEST sense return identifies the actual command @@ -1687,11 +1703,9 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, if (use_10_for_ms && !scsi_status_is_good(result) && (driver_byte(result) & DRIVER_SENSE)) { - struct scsi_sense_hdr sshdr; - - if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { - if ((sshdr.sense_key == ILLEGAL_REQUEST) && - (sshdr.asc == 0x20) && (sshdr.ascq == 0)) { + if (scsi_sense_valid(sshdr)) { + if ((sshdr->sense_key == ILLEGAL_REQUEST) && + (sshdr->asc == 0x20) && (sshdr->ascq == 0)) { /* * Invalid command operation code */ @@ -1718,7 +1732,6 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, } } - kfree(sense_buffer); return result; } EXPORT_SYMBOL(scsi_mode_sense); @@ -1729,17 +1742,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) char cmd[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0, }; - char sense[SCSI_SENSE_BUFFERSIZE]; + struct scsi_sense_hdr sshdr; int result; - result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sense, + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, timeout, retries); if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { - struct scsi_sense_hdr sshdr; - if ((scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, - &sshdr)) && + if ((scsi_sense_valid(&sshdr)) && ((sshdr.sense_key == UNIT_ATTENTION) || (sshdr.sense_key == NOT_READY))) { sdev->changed = 1; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 0048beaffc9..19c9a232a75 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -446,7 +446,6 @@ void scsi_target_reap(struct scsi_target *starget) static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, int result_len, int *bflags) { - char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; @@ -474,11 +473,10 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, scsi_cmd[0] = INQUIRY; scsi_cmd[4] = (unsigned char) try_inquiry_len; - memset(sense, 0, sizeof(sense)); memset(inq_result, 0, try_inquiry_len); result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - inq_result, try_inquiry_len, sense, + inq_result, try_inquiry_len, &sshdr, HZ / 2 + HZ * scsi_inq_timeout, 3); SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " @@ -493,8 +491,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, * but many buggy devices do so anyway. */ if ((driver_byte(result) & DRIVER_SENSE) && - scsi_normalize_sense(sense, sizeof(sense), - &sshdr)) { + scsi_sense_valid(&sshdr)) { if ((sshdr.sense_key == UNIT_ATTENTION) && ((sshdr.asc == 0x28) || (sshdr.asc == 0x29)) && @@ -1057,7 +1054,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, int rescan) { char devname[64]; - char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned int length; unsigned int lun; @@ -1134,9 +1130,8 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, " REPORT LUNS to %s (try %d)\n", devname, retries)); - memset(sense, 0, sizeof(sense)); result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - lun_data, length, sense, + lun_data, length, &sshdr, SCSI_TIMEOUT + 4 * HZ, 3); SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" @@ -1144,7 +1139,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, ? "failed" : "successful", retries, result)); if (result == 0) break; - else if (scsi_normalize_sense(sense, sizeof(sense), &sshdr)) { + else if (scsi_sense_valid(&sshdr)) { if (sshdr.sense_key != UNIT_ATTENTION) break; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 15c2039059c..611ccde8477 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include "scsi_logging.h" @@ -125,7 +124,7 @@ static int sd_issue_flush(struct device *, sector_t *); static void sd_end_flush(request_queue_t *, struct request *); static int sd_prepare_flush(request_queue_t *, struct request *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer); + unsigned char *buffer); static struct scsi_driver sd_template = { .owner = THIS_MODULE, @@ -682,19 +681,13 @@ not_present: static int sd_sync_cache(struct scsi_device *sdp) { - struct scsi_request *sreq; int retries, res; + struct scsi_sense_hdr sshdr; if (!scsi_device_online(sdp)) return -ENODEV; - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk("FAILED\n No memory for request\n"); - return -ENOMEM; - } - sreq->sr_data_direction = DMA_NONE; for (retries = 3; retries > 0; --retries) { unsigned char cmd[10] = { 0 }; @@ -703,22 +696,20 @@ static int sd_sync_cache(struct scsi_device *sdp) * Leave the rest of the command zero to indicate * flush everything. */ - scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); - if (sreq->sr_result == 0) + res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); + if (res == 0) break; } - res = sreq->sr_result; - if (res) { - printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " "host = %d, driver = %02x\n ", status_byte(res), msg_byte(res), host_byte(res), driver_byte(res)); if (driver_byte(res) & DRIVER_SENSE) - scsi_print_req_sense("sd", sreq); + scsi_print_sense_hdr("sd", &sshdr); } - scsi_release_request(sreq); return res; } @@ -957,22 +948,19 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); } -static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) +static int media_not_present(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) { - struct scsi_sense_hdr sshdr; - if (!srp->sr_result) - return 0; - if (!(driver_byte(srp->sr_result) & DRIVER_SENSE)) + if (!scsi_sense_valid(sshdr)) return 0; /* not invoked for commands that could return deferred errors */ - if (scsi_request_normalize_sense(srp, &sshdr)) { - if (sshdr.sense_key != NOT_READY && - sshdr.sense_key != UNIT_ATTENTION) - return 0; - if (sshdr.asc != 0x3A) /* medium not present */ - return 0; - } + if (sshdr->sense_key != NOT_READY && + sshdr->sense_key != UNIT_ATTENTION) + return 0; + if (sshdr->asc != 0x3A) /* medium not present */ + return 0; + set_media_not_present(sdkp); return 1; } @@ -981,8 +969,8 @@ static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) * spinup disk - called only in sd_revalidate_disk() */ static void -sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { +sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) +{ unsigned char cmd[10]; unsigned long spintime_value = 0; int retries, spintime; @@ -1001,18 +989,13 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, cmd[0] = TEST_UNIT_READY; memset((void *) &cmd[1], 0, 9); - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - SRpnt->sr_data_direction = DMA_NONE; + the_result = scsi_execute_req(sdkp->device, cmd, + DMA_NONE, NULL, 0, + &sshdr, SD_TIMEOUT, + SD_MAX_RETRIES); - scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, - 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); - - the_result = SRpnt->sr_result; if (the_result) - sense_valid = scsi_request_normalize_sense( - SRpnt, &sshdr); + sense_valid = scsi_sense_valid(&sshdr); retries++; } while (retries < 3 && (!scsi_status_is_good(the_result) || @@ -1024,7 +1007,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, * any media in it, don't bother with any of the rest of * this crap. */ - if (media_not_present(sdkp, SRpnt)) + if (media_not_present(sdkp, &sshdr)) return; if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { @@ -1063,14 +1046,9 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - - SRpnt->sr_data_direction = DMA_NONE; - scsi_wait_req(SRpnt, (void *)cmd, - (void *) buffer, 0/*512*/, - SD_TIMEOUT, SD_MAX_RETRIES); + scsi_execute_req(sdkp->device, cmd, DMA_NONE, + NULL, 0, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); spintime_value = jiffies; } spintime = 1; @@ -1083,7 +1061,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, if(!spintime) { printk(KERN_NOTICE "%s: Unit Not Ready, " "sense:\n", diskname); - scsi_print_req_sense("", SRpnt); + scsi_print_sense_hdr("", &sshdr); } break; } @@ -1104,14 +1082,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, */ static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + unsigned char *buffer) +{ unsigned char cmd[16]; - struct scsi_device *sdp = sdkp->device; int the_result, retries; int sector_size = 0; int longrc = 0; struct scsi_sense_hdr sshdr; int sense_valid = 0; + struct scsi_device *sdp = sdkp->device; repeat: retries = 3; @@ -1128,20 +1107,15 @@ repeat: memset((void *) buffer, 0, 8); } - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - SRpnt->sr_data_direction = DMA_FROM_DEVICE; - - scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES); + the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, + buffer, longrc ? 12 : 8, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); - if (media_not_present(sdkp, SRpnt)) + if (media_not_present(sdkp, &sshdr)) return; - the_result = SRpnt->sr_result; if (the_result) - sense_valid = scsi_request_normalize_sense(SRpnt, - &sshdr); + sense_valid = scsi_sense_valid(&sshdr); retries--; } while (the_result && retries); @@ -1156,7 +1130,7 @@ repeat: driver_byte(the_result)); if (driver_byte(the_result) & DRIVER_SENSE) - scsi_print_req_sense("sd", SRpnt); + scsi_print_sense_hdr("sd", &sshdr); else printk("%s : sense not available. \n", diskname); @@ -1296,12 +1270,13 @@ got_data: /* called with buffer of length 512 */ static inline int -sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, - unsigned char *buffer, int len, struct scsi_mode_data *data) +sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, + unsigned char *buffer, int len, struct scsi_mode_data *data, + struct scsi_sense_hdr *sshdr) { - return scsi_mode_sense(SRpnt->sr_device, dbd, modepage, buffer, len, + return scsi_mode_sense(sdp, dbd, modepage, buffer, len, SD_TIMEOUT, SD_MAX_RETRIES, data, - SRpnt->sr_sense_buffer); + sshdr); } /* @@ -1310,25 +1285,27 @@ sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, */ static void sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + unsigned char *buffer) +{ int res; + struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; set_disk_ro(sdkp->disk, 0); - if (sdkp->device->skip_ms_page_3f) { + if (sdp->skip_ms_page_3f) { printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname); return; } - if (sdkp->device->use_192_bytes_for_3f) { - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data); + if (sdp->use_192_bytes_for_3f) { + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL); } else { /* * First attempt: ask for all pages (0x3F), but only 4 bytes. * We have to start carefully: some devices hang if we ask * for more than is available. */ - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data); + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 4, &data, NULL); /* * Second attempt: ask for page 0 When only page 0 is @@ -1337,14 +1314,14 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, * CDB. */ if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data); + res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL); /* * Third attempt: ask 255 bytes, as we did earlier. */ if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255, - &data); + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255, + &data, NULL); } if (!scsi_status_is_good(res)) { @@ -1366,19 +1343,20 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, */ static void sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) + unsigned char *buffer) { int len = 0, res; + struct scsi_device *sdp = sdkp->device; int dbd; int modepage; struct scsi_mode_data data; struct scsi_sense_hdr sshdr; - if (sdkp->device->skip_ms_page_8) + if (sdp->skip_ms_page_8) goto defaults; - if (sdkp->device->type == TYPE_RBC) { + if (sdp->type == TYPE_RBC) { modepage = 6; dbd = 8; } else { @@ -1387,7 +1365,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, } /* cautiously ask */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data); + res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr); if (!scsi_status_is_good(res)) goto bad_sense; @@ -1408,7 +1386,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, len += data.header_length + data.block_descriptor_length; /* Get the data */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data); + res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { const char *types[] = { @@ -1440,7 +1418,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, } bad_sense: - if (scsi_request_normalize_sense(SRpnt, &sshdr) && + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST && sshdr.asc == 0x24 && sshdr.ascq == 0x0) printk(KERN_NOTICE "%s: cache data unavailable\n", @@ -1465,7 +1443,6 @@ static int sd_revalidate_disk(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; - struct scsi_request *sreq; unsigned char *buffer; SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); @@ -1477,18 +1454,11 @@ static int sd_revalidate_disk(struct gendisk *disk) if (!scsi_device_online(sdp)) goto out; - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation " - "failure.\n"); - goto out; - } - buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); if (!buffer) { printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " "failure.\n"); - goto out_release_request; + goto out; } /* defaults, until the device tells us otherwise */ @@ -1499,25 +1469,23 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer); + sd_spinup_disk(sdkp, disk->disk_name); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { - sd_read_capacity(sdkp, disk->disk_name, sreq, buffer); + sd_read_capacity(sdkp, disk->disk_name, buffer); if (sdp->removable) sd_read_write_protect_flag(sdkp, disk->disk_name, - sreq, buffer); - sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer); + buffer); + sd_read_cache_type(sdkp, disk->disk_name, buffer); } set_capacity(disk, sdkp->capacity); kfree(buffer); - out_release_request: - scsi_release_request(sreq); out: return 0; } -- cgit v1.2.3 From 820732b501a5bbdd3bde1263f391891e21b5ed8c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 12 Jun 2005 22:21:29 -0500 Subject: [SCSI] convert sr to scsi_execute_req This follows almost the identical model to sd, except that there's one ioctl which returns raw sense data, so it had to use scsi_execute() instead. Signed-off-by: James Bottomley --- drivers/scsi/sr.c | 49 ++++++++------------------------------ drivers/scsi/sr_ioctl.c | 62 +++++++++++++++++++++---------------------------- 2 files changed, 37 insertions(+), 74 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 8cbe6e00418..39fc5b0fbc1 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -50,10 +50,10 @@ #include #include #include +#include #include #include #include /* For the door lock/unlock commands */ -#include #include "scsi_logging.h" #include "sr.h" @@ -658,39 +658,27 @@ static void get_sectorsize(struct scsi_cd *cd) unsigned char *buffer; int the_result, retries = 3; int sector_size; - struct scsi_request *SRpnt = NULL; request_queue_t *queue; buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) goto Enomem; - SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL); - if (!SRpnt) - goto Enomem; do { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); - /* Mark as really busy */ - SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; - SRpnt->sr_cmd_len = 0; - memset(buffer, 0, 8); /* Do the command and wait.. */ - SRpnt->sr_data_direction = DMA_FROM_DEVICE; - scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 8, SR_TIMEOUT, MAX_RETRIES); + the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, + buffer, 8, NULL, SR_TIMEOUT, + MAX_RETRIES); - the_result = SRpnt->sr_result; retries--; } while (the_result && retries); - scsi_release_request(SRpnt); - SRpnt = NULL; - if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ @@ -750,8 +738,6 @@ Enomem: cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ cd->needs_sector_size = 1; - if (SRpnt) - scsi_release_request(SRpnt); goto out; } @@ -759,8 +745,8 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; - struct scsi_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; + struct scsi_sense_hdr sshdr; unsigned int the_result; int retries, rc, n; @@ -776,19 +762,11 @@ static void get_capabilities(struct scsi_cd *cd) "" }; - /* allocate a request for the TEST_UNIT_READY */ - SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL); - if (!SRpnt) { - printk(KERN_WARNING "(get_capabilities:) Request allocation " - "failure.\n"); - return; - } /* allocate transfer buffer */ buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) { printk(KERN_ERR "sr: out of memory.\n"); - scsi_release_request(SRpnt); return; } @@ -800,20 +778,15 @@ static void get_capabilities(struct scsi_cd *cd) memset((void *)cmd, 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; - SRpnt->sr_cmd_len = 0; - SRpnt->sr_sense_buffer[0] = 0; - SRpnt->sr_sense_buffer[2] = 0; - SRpnt->sr_data_direction = DMA_NONE; - - scsi_wait_req (SRpnt, (void *) cmd, buffer, - 0, SR_TIMEOUT, MAX_RETRIES); + the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, + 0, &sshdr, SR_TIMEOUT, + MAX_RETRIES); - the_result = SRpnt->sr_result; retries++; } while (retries < 5 && (!scsi_status_is_good(the_result) || - ((driver_byte(the_result) & DRIVER_SENSE) && - SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); + (scsi_sense_valid(&sshdr) && + sshdr.sense_key == UNIT_ATTENTION))); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, @@ -825,7 +798,6 @@ static void get_capabilities(struct scsi_cd *cd) cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R | CDC_DVD | CDC_DVD_RAM | CDC_SELECT_DISC | CDC_SELECT_SPEED); - scsi_release_request(SRpnt); kfree(buffer); printk("%s: scsi-1 drive\n", cd->cdi.name); return; @@ -885,7 +857,6 @@ static void get_capabilities(struct scsi_cd *cd) cd->device->writeable = 1; } - scsi_release_request(SRpnt); kfree(buffer); } diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 82d68fdb154..6e45ac3c43c 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "sr.h" @@ -84,41 +84,37 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) { - struct scsi_request *SRpnt; struct scsi_device *SDev; - struct request *req; + struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; + struct request_sense *sense = cgc->sense; SDev = cd->device; - SRpnt = scsi_allocate_request(SDev, GFP_KERNEL); - if (!SRpnt) { - printk(KERN_ERR "Unable to allocate SCSI request in sr_do_ioctl"); - err = -ENOMEM; - goto out; - } - SRpnt->sr_data_direction = cgc->data_direction; + + if (!sense) { + sense = kmalloc(sizeof(*sense), GFP_KERNEL); + if (!sense) { + err = -ENOMEM; + goto out; + } + } retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; - goto out_free; + goto out; } - scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen, - cgc->timeout, IOCTL_RETRIES); - - req = SRpnt->sr_request; - if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { - memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen); - kfree(SRpnt->sr_buffer); - SRpnt->sr_buffer = req->buffer; - } + memset(sense, 0, sizeof(*sense)); + result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, + cgc->buffer, cgc->buflen, (char *)sense, + cgc->timeout, IOCTL_RETRIES, 0); - result = SRpnt->sr_result; + scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { - switch (SRpnt->sr_sense_buffer[2] & 0xf) { + switch (sshdr.sense_key) { case UNIT_ATTENTION: SDev->changed = 1; if (!cgc->quiet) @@ -128,8 +124,8 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ - if (SRpnt->sr_sense_buffer[12] == 0x04 && - SRpnt->sr_sense_buffer[13] == 0x01) { + if (sshdr.asc == 0x04 && + sshdr.ascq == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); @@ -146,37 +142,33 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); #ifdef DEBUG - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); #endif err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: err = -EIO; - if (SRpnt->sr_sense_buffer[12] == 0x20 && - SRpnt->sr_sense_buffer[13] == 0x00) + if (sshdr.asc == 0x20 && + sshdr.ascq == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; #ifdef DEBUG __scsi_print_command(cgc->cmd); - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); #endif break; default: printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); __scsi_print_command(cgc->cmd); - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); err = -EIO; } } - if (cgc->sense) - memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense)); - /* Wake up a process waiting for device */ - out_free: - scsi_release_request(SRpnt); - SRpnt = NULL; out: + if (!cgc->sense) + kfree(sense); cgc->stat = err; return err; } -- cgit v1.2.3 From 84743bbcf9fc3767aa33f769898432538281e6dc Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 12 Jun 2005 22:37:10 -0500 Subject: [SCSI] convert ch to use scsi_execute_req I also tinkered with it's sense recognition routines to make them take scsi_sense_hdr structures instead of raw sense data. Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 53b39553431..bd0e1b6be1e 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #define CH_DT_MAX 16 @@ -180,17 +180,17 @@ static struct { /* ------------------------------------------------------------------- */ -static int ch_find_errno(unsigned char *sense_buffer) +static int ch_find_errno(struct scsi_sense_hdr *sshdr) { int i,errno = 0; /* Check to see if additional sense information is available */ - if (sense_buffer[7] > 5 && - sense_buffer[12] != 0) { + if (scsi_sense_valid(sshdr) && + sshdr->asc != 0) { for (i = 0; err[i].errno != 0; i++) { - if (err[i].sense == sense_buffer[ 2] && - err[i].asc == sense_buffer[12] && - err[i].ascq == sense_buffer[13]) { + if (err[i].sense == sshdr->sense_key && + err[i].asc == sshdr->asc && + err[i].ascq == sshdr->ascq) { errno = -err[i].errno; break; } @@ -206,13 +206,9 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, void *buffer, unsigned buflength, enum dma_data_direction direction) { - int errno, retries = 0, timeout; - struct scsi_request *sr; + int errno, retries = 0, timeout, result; + struct scsi_sense_hdr sshdr; - sr = scsi_allocate_request(ch->device, GFP_KERNEL); - if (NULL == sr) - return -ENOMEM; - timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) ? timeout_init : timeout_move; @@ -223,16 +219,17 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, __scsi_print_command(cmd); } - scsi_wait_req(sr, cmd, buffer, buflength, - timeout * HZ, MAX_RETRIES); + result = scsi_execute_req(ch->device, cmd, direction, buffer, + buflength, &sshdr, timeout * HZ, + MAX_RETRIES); - dprintk("result: 0x%x\n",sr->sr_result); - if (driver_byte(sr->sr_result) & DRIVER_SENSE) { + dprintk("result: 0x%x\n",result); + if (driver_byte(result) & DRIVER_SENSE) { if (debug) - scsi_print_req_sense(ch->name, sr); - errno = ch_find_errno(sr->sr_sense_buffer); + scsi_print_sense_hdr(ch->name, &sshdr); + errno = ch_find_errno(&sshdr); - switch(sr->sr_sense_buffer[2] & 0xf) { + switch(sshdr.sense_key) { case UNIT_ATTENTION: ch->unit_attention = 1; if (retries++ < 3) @@ -240,7 +237,6 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, break; } } - scsi_release_request(sr); return errno; } -- cgit v1.2.3 From 1ccb48bb163853c24840c0a50c2a6df1affe029c Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 26 Jun 2005 00:12:51 -0700 Subject: [SCSI] fix C syntax problem in scsi_lib.c Older gcc's require variable definitions at the beginning of a block. Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bdea26b56dc..58da7f64c22 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -336,14 +336,15 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, struct scsi_sense_hdr *sshdr, int timeout, int retries) { char *sense = NULL; - + int result; + if (sshdr) { sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) return DRIVER_ERROR << 24; memset(sense, 0, sizeof(*sense)); } - int result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, + result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, timeout, retries, 0); if (sshdr) scsi_normalize_sense(sense, sizeof(*sense), sshdr); -- cgit v1.2.3 From f189c5cb8ddde0c01838f2b3bc7650e86c097a14 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 19 Jun 2005 11:32:53 +0200 Subject: [SCSI] comment cleanup for spi_execute Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 874042f1899..ef577c8c218 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -106,8 +106,6 @@ static int sprint_frac(char *dest, int value, int denom) return result; } -/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions - * resulting from (likely) bus and device resets */ static int spi_execute(struct scsi_device *sdev, const void *cmd, enum dma_data_direction dir, void *buffer, unsigned bufflen, @@ -117,8 +115,6 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd, unsigned char sense[SCSI_SENSE_BUFFERSIZE]; for(i = 0; i < DV_RETRIES; i++) { - - /* FIXME: need to set REQ_FAILFAST */ result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense, DV_TIMEOUT, /* retries */ 1, REQ_FAILFAST); -- cgit v1.2.3 From c9d297c543f379a27a34082070ed03a8ef846fc2 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 28 Jun 2005 09:18:21 -0500 Subject: [SCSI] fix 3ware raid emulated commands The 3ware emulated commands all expect they are executing in the use_sg == 0 case, which isn't true either in the block layer rework or an SG_IO ioctl. Fix this by adding the correct kmapping of the first element in the sg list. Signed-off-by: James Bottomley --- drivers/scsi/3w-xxxx.c | 57 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 18 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 973c51fb0fe..ae9e0203e9d 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1499,22 +1499,43 @@ static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id) return 0; } /* End tw_scsiop_inquiry() */ +static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, + void *data, unsigned int len) +{ + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + void *buf; + unsigned int transfer_len; + + if (cmd->use_sg) { + struct scatterlist *sg = + (struct scatterlist *)cmd->request_buffer; + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + transfer_len = min(sg->length, len); + } else { + buf = cmd->request_buffer; + transfer_len = min(cmd->request_bufflen, len); + } + + memcpy(buf, data, transfer_len); + + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + kunmap_atomic(buf - sg->offset, KM_IRQ0); + } +} + /* This function is called by the isr to complete an inquiry command */ static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) { unsigned char *is_unit_present; - unsigned char *request_buffer; + unsigned char request_buffer[36]; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n"); - /* Fill request buffer */ - if (tw_dev->srb[request_id]->request_buffer == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n"); - return 1; - } - request_buffer = tw_dev->srb[request_id]->request_buffer; - memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + memset(request_buffer, 0, sizeof(request_buffer)); request_buffer[0] = TYPE_DISK; /* Peripheral device type */ request_buffer[1] = 0; /* Device type modifier */ request_buffer[2] = 0; /* No ansi/iso compliance */ @@ -1522,6 +1543,8 @@ static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_i memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */ sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id); memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3); + tw_transfer_internal(tw_dev, request_id, request_buffer, + sizeof(request_buffer)); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; if (param == NULL) { @@ -1612,7 +1635,7 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques { TW_Param *param; unsigned char *flags; - unsigned char *request_buffer; + unsigned char request_buffer[8]; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n"); @@ -1622,8 +1645,7 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques return 1; } flags = (char *)&(param->data[0]); - request_buffer = tw_dev->srb[request_id]->buffer; - memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + memset(request_buffer, 0, sizeof(request_buffer)); request_buffer[0] = 0xf; /* mode data length */ request_buffer[1] = 0; /* default medium type */ @@ -1635,6 +1657,8 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques request_buffer[6] = 0x4; /* WCE on */ else request_buffer[6] = 0x0; /* WCE off */ + tw_transfer_internal(tw_dev, request_id, request_buffer, + sizeof(request_buffer)); return 0; } /* End tw_scsiop_mode_sense_complete() */ @@ -1701,17 +1725,12 @@ static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int req { unsigned char *param_data; u32 capacity; - char *buff; + char buff[8]; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n"); - buff = tw_dev->srb[request_id]->request_buffer; - if (buff == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n"); - return 1; - } - memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); + memset(buff, 0, sizeof(buff)); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; if (param == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); @@ -1739,6 +1758,8 @@ static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int req buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff; buff[7] = TW_BLOCK_SIZE & 0xff; + tw_transfer_internal(tw_dev, request_id, buff, sizeof(buff)); + return 0; } /* End tw_scsiop_read_capacity_complete() */ -- cgit v1.2.3 From e514385be2b355c1f3fc6385a98a6a0fc04235ae Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 9 Aug 2005 11:55:36 -0500 Subject: [SCSI] fix sense buffer length handling problem The new bio code was incorrectly converted from stack allocated to kmalloc'd buffer handling. There are two places where it incorrectly uses sizeof(*sense) to get the size of the sense buffer. This actually produces one, so no sense data was ever getting back, causing failure in things like disk spin up. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 58da7f64c22..72a47ce7a1d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -342,12 +342,12 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) return DRIVER_ERROR << 24; - memset(sense, 0, sizeof(*sense)); + memset(sense, 0, SCSI_SENSE_BUFFERSIZE); } result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, timeout, retries, 0); if (sshdr) - scsi_normalize_sense(sense, sizeof(*sense), sshdr); + scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr); kfree(sense); return result; -- cgit v1.2.3 From 61a7afa2c476a3be261cf88a95b0dea0c3bd29d4 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 16 Aug 2005 18:27:34 -0500 Subject: [SCSI] embryonic RAID class The idea behind a RAID class is to provide a uniform interface to all RAID subsystems (both hardware and software) in the kernel. To do that, I've made this class a transport class that's entirely subsystem independent (although the matching routines have to match per subsystem, as you'll see looking at the code). I put it in the scsi subdirectory purely because I needed somewhere to play with it, but it's not a scsi specific module. I used a fusion raid card as the test bed for this; with that kind of card, this is the type of class output you get: jejb@titanic> ls -l /sys/class/raid_devices/20\:0\:0\:0/ total 0 lrwxrwxrwx 1 root root 0 Aug 16 17:21 component-0 -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:1:0/20:1:0:0/ lrwxrwxrwx 1 root root 0 Aug 16 17:21 component-1 -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:1:1/20:1:1:0/ lrwxrwxrwx 1 root root 0 Aug 16 17:21 device -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:0:0/20:0:0:0/ -r--r--r-- 1 root root 16384 Aug 16 17:21 level -r--r--r-- 1 root root 16384 Aug 16 17:21 resync -r--r--r-- 1 root root 16384 Aug 16 17:21 state So it's really simple: for a SCSI device representing a hardware raid, it shows the raid level, the array state, the resync % complete (if the state is resyncing) and the underlying components of the RAID (these are exposed in fusion on the virtual channel 1). As you can see, this type of information can be exported by almost anything, including software raid. The more difficult trick, of course, is going to be getting it to perform configuration type actions with writable attributes. Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 6 ++ drivers/scsi/Makefile | 2 + drivers/scsi/raid_class.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 drivers/scsi/raid_class.c (limited to 'drivers/scsi') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 96df148ed96..68adc3cc8ad 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1,5 +1,11 @@ menu "SCSI device support" +config RAID_ATTRS + tristate "RAID Transport Class" + default n + ---help--- + Provides RAID + config SCSI tristate "SCSI device support" ---help--- diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 3746fb9fa2f..85f9e6bb34b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -22,6 +22,8 @@ subdir-$(CONFIG_PCMCIA) += pcmcia obj-$(CONFIG_SCSI) += scsi_mod.o +obj-$(CONFIG_RAID_ATTRS) += raid_class.o + # --- NOTE ORDERING HERE --- # For kernel non-modular link, transport attributes need to # be initialised before drivers diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c new file mode 100644 index 00000000000..f1ea5027865 --- /dev/null +++ b/drivers/scsi/raid_class.c @@ -0,0 +1,250 @@ +/* + * RAID Attributes + */ +#include +#include +#include +#include +#include +#include + +#define RAID_NUM_ATTRS 3 + +struct raid_internal { + struct raid_template r; + struct raid_function_template *f; + /* The actual attributes */ + struct class_device_attribute private_attrs[RAID_NUM_ATTRS]; + /* The array of null terminated pointers to attributes + * needed by scsi_sysfs.c */ + struct class_device_attribute *attrs[RAID_NUM_ATTRS + 1]; +}; + +struct raid_component { + struct list_head node; + struct device *dev; + int num; +}; + +#define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r) + +#define tc_to_raid_internal(tcont) ({ \ + struct raid_template *r = \ + container_of(tcont, struct raid_template, raid_attrs); \ + to_raid_internal(r); \ +}) + +#define ac_to_raid_internal(acont) ({ \ + struct transport_container *tc = \ + container_of(acont, struct transport_container, ac); \ + tc_to_raid_internal(tc); \ +}) + +#define class_device_to_raid_internal(cdev) ({ \ + struct attribute_container *ac = \ + attribute_container_classdev_to_container(cdev); \ + ac_to_raid_internal(ac); \ +}) + + +static int raid_match(struct attribute_container *cont, struct device *dev) +{ + /* We have to look for every subsystem that could house + * emulated RAID devices, so start with SCSI */ + struct raid_internal *i = ac_to_raid_internal(cont); + + if (scsi_is_sdev_device(dev)) { + struct scsi_device *sdev = to_scsi_device(dev); + + if (i->f->cookie != sdev->host->hostt) + return 0; + + return i->f->is_raid(dev); + } + /* FIXME: look at other subsystems too */ + return 0; +} + +static int raid_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct raid_data *rd; + + BUG_ON(class_get_devdata(cdev)); + + rd = kmalloc(sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + memset(rd, 0, sizeof(*rd)); + INIT_LIST_HEAD(&rd->component_list); + class_set_devdata(cdev, rd); + + return 0; +} + +static int raid_remove(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct raid_data *rd = class_get_devdata(cdev); + struct raid_component *rc, *next; + class_set_devdata(cdev, NULL); + list_for_each_entry_safe(rc, next, &rd->component_list, node) { + char buf[40]; + snprintf(buf, sizeof(buf), "component-%d", rc->num); + list_del(&rc->node); + sysfs_remove_link(&cdev->kobj, buf); + kfree(rc); + } + kfree(class_get_devdata(cdev)); + return 0; +} + +static DECLARE_TRANSPORT_CLASS(raid_class, + "raid_devices", + raid_setup, + raid_remove, + NULL); + +static struct { + enum raid_state value; + char *name; +} raid_states[] = { + { RAID_ACTIVE, "active" }, + { RAID_DEGRADED, "degraded" }, + { RAID_RESYNCING, "resyncing" }, + { RAID_OFFLINE, "offline" }, +}; + +static const char *raid_state_name(enum raid_state state) +{ + int i; + char *name = NULL; + + for (i = 0; i < sizeof(raid_states)/sizeof(raid_states[0]); i++) { + if (raid_states[i].value == state) { + name = raid_states[i].name; + break; + } + } + return name; +} + + +#define raid_attr_show_internal(attr, fmt, var, code) \ +static ssize_t raid_show_##attr(struct class_device *cdev, char *buf) \ +{ \ + struct raid_data *rd = class_get_devdata(cdev); \ + code \ + return snprintf(buf, 20, #fmt "\n", var); \ +} + +#define raid_attr_ro_states(attr, states, code) \ +raid_attr_show_internal(attr, %s, name, \ + const char *name; \ + code \ + name = raid_##states##_name(rd->attr); \ +) \ +static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) + + +#define raid_attr_ro_internal(attr, code) \ +raid_attr_show_internal(attr, %d, rd->attr, code) \ +static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) + +#define ATTR_CODE(attr) \ + struct raid_internal *i = class_device_to_raid_internal(cdev); \ + if (i->f->get_##attr) \ + i->f->get_##attr(cdev->dev); + +#define raid_attr_ro(attr) raid_attr_ro_internal(attr, ) +#define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr)) +#define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr)) + +raid_attr_ro(level); +raid_attr_ro_fn(resync); +raid_attr_ro_state(state); + +void raid_component_add(struct raid_template *r,struct device *raid_dev, + struct device *component_dev) +{ + struct class_device *cdev = + attribute_container_find_class_device(&r->raid_attrs.ac, + raid_dev); + struct raid_component *rc; + struct raid_data *rd = class_get_devdata(cdev); + char buf[40]; + + rc = kmalloc(sizeof(*rc), GFP_KERNEL); + if (!rc) + return; + + INIT_LIST_HEAD(&rc->node); + rc->dev = component_dev; + rc->num = rd->component_count++; + + snprintf(buf, sizeof(buf), "component-%d", rc->num); + list_add_tail(&rc->node, &rd->component_list); + sysfs_create_link(&cdev->kobj, &component_dev->kobj, buf); +} +EXPORT_SYMBOL(raid_component_add); + +struct raid_template * +raid_class_attach(struct raid_function_template *ft) +{ + struct raid_internal *i = kmalloc(sizeof(struct raid_internal), + GFP_KERNEL); + int count = 0; + + if (unlikely(!i)) + return NULL; + + memset(i, 0, sizeof(*i)); + + i->f = ft; + + i->r.raid_attrs.ac.class = &raid_class.class; + i->r.raid_attrs.ac.match = raid_match; + i->r.raid_attrs.ac.attrs = &i->attrs[0]; + + attribute_container_register(&i->r.raid_attrs.ac); + + i->attrs[count++] = &class_device_attr_level; + i->attrs[count++] = &class_device_attr_resync; + i->attrs[count++] = &class_device_attr_state; + + i->attrs[count] = NULL; + BUG_ON(count > RAID_NUM_ATTRS); + + return &i->r; +} +EXPORT_SYMBOL(raid_class_attach); + +void +raid_class_release(struct raid_template *r) +{ + struct raid_internal *i = to_raid_internal(r); + + attribute_container_unregister(&i->r.raid_attrs.ac); + + kfree(i); +} +EXPORT_SYMBOL(raid_class_release); + +static __init int raid_init(void) +{ + return transport_class_register(&raid_class); +} + +static __exit void raid_exit(void) +{ + transport_class_unregister(&raid_class); +} + +MODULE_AUTHOR("James Bottomley"); +MODULE_DESCRIPTION("RAID device class"); +MODULE_LICENSE("GPL"); + +module_init(raid_init); +module_exit(raid_exit); + -- cgit v1.2.3 From 07542b832309b93a2741cd162a391ab909f66438 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 31 Aug 2005 20:27:22 -0400 Subject: This patch fixes in st.c the bug in the signed/unsigned int comparison reported by Doug Gilbert and fixed by him in sg.c (see [PATCH] sg direct io/mmap oops). Doug fixed the comparison in sg.c. This fix for st.c does not touch the comparison but makes both arguments signed to remove the problem. The new code is adapted from linux/fs/bio.c. Signed-off-by: Kai Makisara Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/st.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 47a5698a712..5325cf0ab19 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20050802"; +static char *verstr = "20050830"; #include @@ -4444,12 +4444,12 @@ static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pag static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, unsigned long uaddr, size_t count, int rw) { + unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int nr_pages = end - start; int res, i, j; - unsigned int nr_pages; struct page **pages; - nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; - /* User attempted Overflow! */ if ((uaddr + count) < uaddr) return -EINVAL; -- cgit v1.2.3 From deb92b7ee98e8e580cafaa63bd1edbe6646877bc Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Thu, 1 Sep 2005 21:50:02 +1000 Subject: [SCSI] sg direct io/mmap oops, st sync This patch adopts the same solution as proposed by Kai M. in a post titled: "[PATCH] SCSI tape signed/unsigned fix". The fix is in a function that the sg driver borrowed from the st driver so its maintenance is a little easier if the functions remain the same after the fix. - change nr_pages type from unsigned to signed so errors from get_user_pages() call are properly handled Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 14fb179b384..616c3f3e62f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -61,7 +61,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20050328"; +static char *sg_version_date = "20050901"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -1794,12 +1794,12 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, unsigned long uaddr, size_t count, int rw, unsigned long max_pfn) { + unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int nr_pages = end - start; int res, i, j; - unsigned int nr_pages; struct page **pages; - nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; - /* User attempted Overflow! */ if ((uaddr + count) < uaddr) return -EINVAL; -- cgit v1.2.3 From 77d71d222e871670300f3e3092e2a06f20c842f0 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Thu, 1 Sep 2005 08:19:23 -0700 Subject: [SCSI] aacraid: bad BUG_ON fix This was noticed by Doug Bazamic and the fix found by Mark Salyzyn at Adaptec. There was an error in the BUG_ON() statement that validated the calculated fib size which can cause the driver to panic. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 83bfab73ff6..a8e3dfcd0dc 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -972,7 +972,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize = sizeof(struct aac_read64) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentry64)); - BUG_ON (fibsize > (sizeof(struct hw_fib) - + BUG_ON (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))); /* * Now send the Fib to the adapter -- cgit v1.2.3 From 1ff927306e08b356d764e605eff7c50079550bd2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Aug 2005 18:57:13 +0200 Subject: [SCSI] aic7xxx: remove aiclib.c #include of C files and macro tricks to rename symbols are evil and just cause trouble. Let's doublicate the two functions as they're going to go away soon enough anyway. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 96 ++++++++++++++++++++++++---- drivers/scsi/aic7xxx/aic79xx_proc.c | 45 +++++++++++++- drivers/scsi/aic7xxx/aic7xxx_osm.c | 89 +++++++++++++++++++++++--- drivers/scsi/aic7xxx/aic7xxx_proc.c | 45 +++++++++++++- drivers/scsi/aic7xxx/aiclib.c | 121 ------------------------------------ drivers/scsi/aic7xxx/aiclib.h | 22 ------- 6 files changed, 253 insertions(+), 165 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 3feb739cd55..6b6d4e28779 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -48,12 +48,6 @@ static struct scsi_transport_template *ahd_linux_transport_template = NULL; -/* - * Include aiclib.c as part of our - * "module dependencies are hard" work around. - */ -#include "aiclib.c" - #include /* __setup */ #include /* For fetching system memory size */ #include /* For block_size() */ @@ -372,8 +366,6 @@ static int ahd_linux_run_command(struct ahd_softc*, struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); -static aic_option_callback_t ahd_linux_setup_tag_info; -static aic_option_callback_t ahd_linux_setup_iocell_info; static int aic79xx_setup(char *c); static int ahd_linux_unit; @@ -907,6 +899,86 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) } } +static char * +ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, + void (*callback)(u_long, int, int, int32_t), + u_long callback_arg) +{ + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + /* All options use a ':' name/arg separator */ + if (*opt_arg != ':') + return (opt_arg); + opt_arg++; + instance = -1; + targ = -1; + done = FALSE; + /* + * Restore separator that may be in + * the middle of our option argument. + */ + tok_end = strchr(opt_arg, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*opt_arg) { + case '{': + if (instance == -1) { + instance = 0; + } else { + if (depth > 1) { + if (targ == -1) + targ = 0; + } else { + printf("Malformed Option %s\n", + opt_name); + done = TRUE; + } + } + opt_arg++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + opt_arg++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + opt_arg++; + break; + case '\0': + done = TRUE; + break; + default: + tok_end = end; + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(opt_arg, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) + tok_end = tok_end2; + } + callback(callback_arg, instance, targ, + simple_strtol(opt_arg, NULL, 0)); + opt_arg = tok_end; + break; + } + } + return (opt_arg); +} + /* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. @@ -964,18 +1036,18 @@ aic79xx_setup(char *s) if (strncmp(p, "global_tag_depth", n) == 0) { ahd_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { - s = aic_parse_brace_option("tag_info", p + n, end, + s = ahd_parse_brace_option("tag_info", p + n, end, 2, ahd_linux_setup_tag_info, 0); } else if (strncmp(p, "slewrate", n) == 0) { - s = aic_parse_brace_option("slewrate", + s = ahd_parse_brace_option("slewrate", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_SLEWRATE_INDEX); } else if (strncmp(p, "precomp", n) == 0) { - s = aic_parse_brace_option("precomp", + s = ahd_parse_brace_option("precomp", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_PRECOMP_INDEX); } else if (strncmp(p, "amplitude", n) == 0) { - s = aic_parse_brace_option("amplitude", + s = ahd_parse_brace_option("amplitude", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_AMPLITUDE_INDEX); } else if (p[n] == ':') { diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 32be1f55998..39a27840fce 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -53,6 +53,49 @@ static void ahd_dump_device_state(struct info_str *info, static int ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length); +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 100ths of ns */ +} scsi_syncrates[] = { + { 0x08, 625 }, /* FAST-160 */ + { 0x09, 1250 }, /* FAST-80 */ + { 0x0a, 2500 }, /* FAST-40 40MHz */ + { 0x0b, 3030 }, /* FAST-40 33MHz */ + { 0x0c, 5000 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +static u_int +ahd_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (100000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + + static void copy_mem_info(struct info_str *info, char *data, int len) { @@ -109,7 +152,7 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) speed = 3300; freq = 0; if (tinfo->offset != 0) { - freq = aic_calc_syncsrate(tinfo->period); + freq = ahd_calc_syncsrate(tinfo->period); speed = freq; } speed *= (0x01 << tinfo->width); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 22434849de4..4096d523d08 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -125,12 +125,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL; -/* - * Include aiclib.c as part of our - * "module dependencies are hard" work around. - */ -#include "aiclib.c" - #include /* __setup */ #include /* For fetching system memory size */ #include /* For block_size() */ @@ -391,7 +385,6 @@ static int ahc_linux_run_command(struct ahc_softc*, struct ahc_linux_device *, struct scsi_cmnd *); static void ahc_linux_setup_tag_info_global(char *p); -static aic_option_callback_t ahc_linux_setup_tag_info; static int aic7xxx_setup(char *s); static int ahc_linux_unit; @@ -920,6 +913,86 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) } } +static char * +ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, + void (*callback)(u_long, int, int, int32_t), + u_long callback_arg) +{ + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + /* All options use a ':' name/arg separator */ + if (*opt_arg != ':') + return (opt_arg); + opt_arg++; + instance = -1; + targ = -1; + done = FALSE; + /* + * Restore separator that may be in + * the middle of our option argument. + */ + tok_end = strchr(opt_arg, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*opt_arg) { + case '{': + if (instance == -1) { + instance = 0; + } else { + if (depth > 1) { + if (targ == -1) + targ = 0; + } else { + printf("Malformed Option %s\n", + opt_name); + done = TRUE; + } + } + opt_arg++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + opt_arg++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + opt_arg++; + break; + case '\0': + done = TRUE; + break; + default: + tok_end = end; + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(opt_arg, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) + tok_end = tok_end2; + } + callback(callback_arg, instance, targ, + simple_strtol(opt_arg, NULL, 0)); + opt_arg = tok_end; + break; + } + } + return (opt_arg); +} + /* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. @@ -974,7 +1047,7 @@ aic7xxx_setup(char *s) if (strncmp(p, "global_tag_depth", n) == 0) { ahc_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { - s = aic_parse_brace_option("tag_info", p + n, end, + s = ahc_parse_brace_option("tag_info", p + n, end, 2, ahc_linux_setup_tag_info, 0); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 3802c91f0b0..04a3506cf34 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -54,6 +54,49 @@ static void ahc_dump_device_state(struct info_str *info, static int ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length); +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 100ths of ns */ +} scsi_syncrates[] = { + { 0x08, 625 }, /* FAST-160 */ + { 0x09, 1250 }, /* FAST-80 */ + { 0x0a, 2500 }, /* FAST-40 40MHz */ + { 0x0b, 3030 }, /* FAST-40 33MHz */ + { 0x0c, 5000 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +static u_int +ahc_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (100000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + + static void copy_mem_info(struct info_str *info, char *data, int len) { @@ -106,7 +149,7 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo) speed = 3300; freq = 0; if (tinfo->offset != 0) { - freq = aic_calc_syncsrate(tinfo->period); + freq = ahc_calc_syncsrate(tinfo->period); speed = freq; } speed *= (0x01 << tinfo->width); diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 4d44a921118..828ae3d9a51 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -32,124 +32,3 @@ #include "aiclib.h" - -/* - * Table of syncrates that don't follow the "divisible by 4" - * rule. This table will be expanded in future SCSI specs. - */ -static struct { - u_int period_factor; - u_int period; /* in 100ths of ns */ -} scsi_syncrates[] = { - { 0x08, 625 }, /* FAST-160 */ - { 0x09, 1250 }, /* FAST-80 */ - { 0x0a, 2500 }, /* FAST-40 40MHz */ - { 0x0b, 3030 }, /* FAST-40 33MHz */ - { 0x0c, 5000 } /* FAST-20 */ -}; - -/* - * Return the frequency in kHz corresponding to the given - * sync period factor. - */ -u_int -aic_calc_syncsrate(u_int period_factor) -{ - int i; - int num_syncrates; - - num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); - /* See if the period is in the "exception" table */ - for (i = 0; i < num_syncrates; i++) { - - if (period_factor == scsi_syncrates[i].period_factor) { - /* Period in kHz */ - return (100000000 / scsi_syncrates[i].period); - } - } - - /* - * Wasn't in the table, so use the standard - * 4 times conversion. - */ - return (10000000 / (period_factor * 4 * 10)); -} - -char * -aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, - aic_option_callback_t *callback, u_long callback_arg) -{ - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - /* All options use a ':' name/arg separator */ - if (*opt_arg != ':') - return (opt_arg); - opt_arg++; - instance = -1; - targ = -1; - done = FALSE; - /* - * Restore separator that may be in - * the middle of our option argument. - */ - tok_end = strchr(opt_arg, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*opt_arg) { - case '{': - if (instance == -1) { - instance = 0; - } else { - if (depth > 1) { - if (targ == -1) - targ = 0; - } else { - printf("Malformed Option %s\n", - opt_name); - done = TRUE; - } - } - opt_arg++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - opt_arg++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - opt_arg++; - break; - case '\0': - done = TRUE; - break; - default: - tok_end = end; - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(opt_arg, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) - tok_end = tok_end2; - } - callback(callback_arg, instance, targ, - simple_strtol(opt_arg, NULL, 0)); - opt_arg = tok_end; - break; - } - } - return (opt_arg); -} diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index e7d94cbaf2a..3bfbf0fe1ec 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -141,28 +141,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors) return (int)capacity; } -/**************************** Module Library Hack *****************************/ -/* - * What we'd like to do is have a single "scsi library" module that both the - * aic7xxx and aic79xx drivers could load and depend on. A cursory examination - * of implementing module dependencies in Linux (handling the install and - * initrd cases) does not look promissing. For now, we just duplicate this - * code in both drivers using a simple symbol renaming scheme that hides this - * hack from the drivers. - */ -#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x -#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) -#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) - -#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) - -u_int aic_calc_syncsrate(u_int /*period_factor*/); - -typedef void aic_option_callback_t(u_long, int, int, int32_t); -char * aic_parse_brace_option(char *opt_name, char *opt_arg, - char *end, int depth, - aic_option_callback_t *, u_long); - static __inline uint32_t scsi_4btoul(uint8_t *bytes) { -- cgit v1.2.3 From 7524f9b9e72cd36f0a70defcd424eba81c180f42 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:00 -0700 Subject: [SCSI] qla2xxx: Use dma_get_required_mask() in determining the 'ideal' DMA mask. In order to efficiently utilise the ISP's IOCB request-queue, use the dma_get_required_mask() function to determine the use of command-type 2 or 3 IOCBs when queueing SCSI commands. This applies to ISP2[123]xx chips only, as the ISP24xx uses command-type 7 IOCBs which use 64bit DSDs. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9000659bfbc..995e521b07d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1113,36 +1113,23 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha) { - /* Assume 32bit DMA address */ + /* Assume a 32bit DMA mask. */ ha->flags.enable_64bit_addressing = 0; - /* - * Given the two variants pci_set_dma_mask(), allow the compiler to - * assist in setting the proper dma mask. - */ - if (sizeof(dma_addr_t) > 4) { - if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { + if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) { + /* Any upper-dword bits set? */ + if (MSD(dma_get_required_mask(&ha->pdev->dev)) && + !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + /* Ok, a 64bit DMA mask is applicable. */ ha->flags.enable_64bit_addressing = 1; ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64; - - if (pci_set_consistent_dma_mask(ha->pdev, - DMA_64BIT_MASK)) { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); - pci_set_consistent_dma_mask(ha->pdev, - DMA_32BIT_MASK); - } - } else { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI DMA mask, falling back " - "to 32 bit MASK.\n"); - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); + return; } - } else { - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); } + + dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK); + pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK); } static int -- cgit v1.2.3 From ad3e0edaceb9771be7ffbd7aa24fb444a7ed85bf Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:10 -0700 Subject: [SCSI] qla2xxx: Export class-of-service (COS) information. Export COS information for the fc_host and fc_remote_port objects added by the driver. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 4 ++++ drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 7 +++++++ drivers/scsi/qla2xxx/qla_mbx.c | 14 ++++++++++++++ 4 files changed, 26 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 659a5d63467..d05280eecc6 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -304,10 +304,13 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, + .show_host_supported_classes = 1, + .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, .dd_fcrport_size = sizeof(struct fc_port *), + .show_rport_supported_classes = 1, .get_starget_node_name = qla2x00_get_starget_node_name, .show_starget_node_name = 1, @@ -329,4 +332,5 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha) be64_to_cpu(*(uint64_t *)ha->init_cb->node_name); fc_host_port_name(ha->host) = be64_to_cpu(*(uint64_t *)ha->init_cb->port_name); + fc_host_supported_classes(ha->host) = FC_COS_CLASS3; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1c6d366f4fa..38848c38ad8 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1673,6 +1673,7 @@ typedef struct fc_port { uint8_t cur_path; /* current path id */ struct fc_rport *rport; + u32 supported_classes; } fc_port_t; /* diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a6d2559217c..09b23f70fd6 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1697,6 +1697,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; atomic_set(&fcport->state, FCS_UNCONFIGURED); fcport->flags = FCF_RLC_SUPPORT; + fcport->supported_classes = FC_COS_UNSPECIFIED; return (fcport); } @@ -2075,6 +2076,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) return; } rport->dd_data = fcport; + rport->supported_classes = fcport->supported_classes; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; if (fcport->port_type == FCT_INITIATOR) @@ -2794,6 +2796,11 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport, } } + if (mb[10] & BIT_0) + fcport->supported_classes |= FC_COS_CLASS2; + if (mb[10] & BIT_1) + fcport->supported_classes |= FC_COS_CLASS3; + rval = QLA_SUCCESS; break; } else if (mb[0] == MBS_LOOP_ID_USED) { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 409ea0ac403..774309a77c0 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -19,6 +19,7 @@ #include "qla_def.h" #include +#include static void qla2x00_mbx_sem_timeout(unsigned long data) @@ -1326,6 +1327,10 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) fcport->port_type = FCT_INITIATOR; else fcport->port_type = FCT_TARGET; + + /* Passback COS information. */ + fcport->supported_classes = (pd->options & BIT_4) ? + FC_COS_CLASS2: FC_COS_CLASS3; } gpd_error_out: @@ -1661,6 +1666,13 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[1] |= BIT_1; } else mb[1] = BIT_0; + + /* Passback COS information. */ + mb[10] = 0; + if (lg->io_parameter[7] || lg->io_parameter[8]) + mb[10] |= BIT_0; /* Class 2. */ + if (lg->io_parameter[9] || lg->io_parameter[10]) + mb[10] |= BIT_1; /* Class 3. */ } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1723,6 +1735,8 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[2] = mcp->mb[2]; mb[6] = mcp->mb[6]; mb[7] = mcp->mb[7]; + /* COS retrieved from Get-Port-Database mailbox command. */ + mb[10] = 0; } if (rval != QLA_SUCCESS) { -- cgit v1.2.3 From cca5335caf2d19ef8bd6b833445d2c6ca652a89b Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:30 -0700 Subject: [SCSI] qla2xxx: Add FDMI support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.h | 7 + drivers/scsi/qla2xxx/qla_def.h | 151 ++++++++++- drivers/scsi/qla2xxx/qla_gbl.h | 4 + drivers/scsi/qla2xxx/qla_gs.c | 564 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_init.c | 6 + drivers/scsi/qla2xxx/qla_isr.c | 2 + drivers/scsi/qla2xxx/qla_mbx.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 10 + 8 files changed, 741 insertions(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index b8d90e97e01..9684e7a91fa 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -81,6 +81,7 @@ #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 @@ -169,8 +170,14 @@ #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_def.h b/drivers/scsi/qla2xxx/qla_def.h index 38848c38ad8..cdef86e49c6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -214,6 +214,7 @@ * valid range of an N-PORT id is 0 through 0x7ef. */ #define NPH_LAST_HANDLE 0x7ef +#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */ #define NPH_SNS 0x7fc /* FFFFFC */ #define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */ #define NPH_F_PORT 0x7fe /* FFFFFE */ @@ -1131,10 +1132,7 @@ typedef struct { uint8_t link_down_timeout; - uint8_t adapter_id_0[4]; - uint8_t adapter_id_1[4]; - uint8_t adapter_id_2[4]; - uint8_t adapter_id_3[4]; + uint8_t adapter_id[16]; uint8_t alt1_boot_node_name[WWN_SIZE]; uint16_t alt1_boot_lun_number; @@ -1728,6 +1726,8 @@ typedef struct fc_port { #define CT_REJECT_RESPONSE 0x8001 #define CT_ACCEPT_RESPONSE 0x8002 +#define CT_REASON_CANNOT_PERFORM 0x09 +#define CT_EXPL_ALREADY_REGISTERED 0x10 #define NS_N_PORT_TYPE 0x01 #define NS_NL_PORT_TYPE 0x02 @@ -1769,6 +1769,100 @@ typedef struct fc_port { #define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) #define RSNN_NN_RSP_SIZE 16 +/* + * HBA attribute types. + */ +#define FDMI_HBA_ATTR_COUNT 9 +#define FDMI_HBA_NODE_NAME 1 +#define FDMI_HBA_MANUFACTURER 2 +#define FDMI_HBA_SERIAL_NUMBER 3 +#define FDMI_HBA_MODEL 4 +#define FDMI_HBA_MODEL_DESCRIPTION 5 +#define FDMI_HBA_HARDWARE_VERSION 6 +#define FDMI_HBA_DRIVER_VERSION 7 +#define FDMI_HBA_OPTION_ROM_VERSION 8 +#define FDMI_HBA_FIRMWARE_VERSION 9 +#define FDMI_HBA_OS_NAME_AND_VERSION 0xa +#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb + +struct ct_fdmi_hba_attr { + uint16_t type; + uint16_t len; + union { + uint8_t node_name[WWN_SIZE]; + uint8_t manufacturer[32]; + uint8_t serial_num[8]; + uint8_t model[16]; + uint8_t model_desc[80]; + uint8_t hw_version[16]; + uint8_t driver_version[32]; + uint8_t orom_version[16]; + uint8_t fw_version[16]; + uint8_t os_version[128]; + uint8_t max_ct_len[4]; + } a; +}; + +struct ct_fdmi_hba_attributes { + uint32_t count; + struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; +}; + +/* + * Port attribute types. + */ +#define FDMI_PORT_ATTR_COUNT 5 +#define FDMI_PORT_FC4_TYPES 1 +#define FDMI_PORT_SUPPORT_SPEED 2 +#define FDMI_PORT_CURRENT_SPEED 3 +#define FDMI_PORT_MAX_FRAME_SIZE 4 +#define FDMI_PORT_OS_DEVICE_NAME 5 +#define FDMI_PORT_HOST_NAME 6 + +struct ct_fdmi_port_attr { + uint16_t type; + uint16_t len; + union { + uint8_t fc4_types[32]; + uint32_t sup_speed; + uint32_t cur_speed; + uint32_t max_frame_size; + uint8_t os_dev_name[32]; + uint8_t host_name[32]; + } a; +}; + +/* + * Port Attribute Block. + */ +struct ct_fdmi_port_attributes { + uint32_t count; + struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; +}; + +/* FDMI definitions. */ +#define GRHL_CMD 0x100 +#define GHAT_CMD 0x101 +#define GRPL_CMD 0x102 +#define GPAT_CMD 0x110 + +#define RHBA_CMD 0x200 +#define RHBA_RSP_SIZE 16 + +#define RHAT_CMD 0x201 +#define RPRT_CMD 0x210 + +#define RPA_CMD 0x211 +#define RPA_RSP_SIZE 16 + +#define DHBA_CMD 0x300 +#define DHBA_REQ_SIZE (16 + 8) +#define DHBA_RSP_SIZE 16 + +#define DHAT_CMD 0x301 +#define DPRT_CMD 0x310 +#define DPA_CMD 0x311 + /* CT command header -- request/response common fields */ struct ct_cmd_hdr { uint8_t revision; @@ -1826,6 +1920,43 @@ struct ct_sns_req { uint8_t name_len; uint8_t sym_node_name[255]; } rsnn_nn; + + struct { + uint8_t hba_indentifier[8]; + } ghat; + + struct { + uint8_t hba_identifier[8]; + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } rhba; + + struct { + uint8_t hba_identifier[8]; + struct ct_fdmi_hba_attributes attrs; + } rhat; + + struct { + uint8_t port_name[8]; + struct ct_fdmi_port_attributes attrs; + } rpa; + + struct { + uint8_t port_name[8]; + } dhba; + + struct { + uint8_t port_name[8]; + } dhat; + + struct { + uint8_t port_name[8]; + } dprt; + + struct { + uint8_t port_name[8]; + } dpa; } req; }; @@ -1883,6 +2014,12 @@ struct ct_sns_rsp { struct { uint8_t fc4_types[32]; } gft_id; + + struct { + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } ghat; } rsp; }; @@ -2033,6 +2170,8 @@ struct isp_operations { uint16_t (*calc_req_entries) (uint16_t); void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t); void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t); + void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t, + uint32_t); uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); @@ -2112,6 +2251,7 @@ typedef struct scsi_qla_host { #define IOCTL_ERROR_RECOVERY 23 #define LOOP_RESET_NEEDED 24 #define BEACON_BLINK_NEEDED 25 +#define REGISTER_FDMI_NEEDED 26 uint32_t device_flags; #define DFLG_LOCAL_DEVICES BIT_0 @@ -2205,6 +2345,7 @@ typedef struct scsi_qla_host { int port_down_retry_count; uint8_t mbx_count; uint16_t last_loop_id; + uint16_t mgmt_svr_loop_id; uint32_t login_retry_count; @@ -2319,6 +2460,7 @@ typedef struct scsi_qla_host { uint8_t model_number[16+1]; #define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" char *model_desc; + uint8_t adapter_id[16+1]; uint8_t *node_name; uint8_t *port_name; @@ -2378,6 +2520,7 @@ typedef struct scsi_qla_host { #define QLA_SUSPENDED 0x106 #define QLA_BUSY 0x107 #define QLA_RSCNS_HANDLED 0x108 +#define QLA_ALREADY_REGISTERED 0x109 /* * Stat info for all adpaters diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 665c203e067..3e1e5fe850a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -79,6 +79,7 @@ extern int ql2xplogiabsentdevice; extern int ql2xenablezio; extern int ql2xintrdelaytimer; extern int ql2xloginretrycount; +extern int ql2xfdmienable; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -269,6 +270,9 @@ extern int qla2x00_rft_id(scsi_qla_host_t *); extern int qla2x00_rff_id(scsi_qla_host_t *); extern int qla2x00_rnn_id(scsi_qla_host_t *); extern int qla2x00_rsnn_nn(scsi_qla_host_t *); +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_rscn.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 31ce4f62da1..e7b138c2e33 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1099,3 +1099,567 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha) return (rval); } + +/** + * qla2x00_mgmt_svr_login() - Login to fabric Managment Service. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_mgmt_svr_login(scsi_qla_host_t *ha) +{ + int ret; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ret = QLA_SUCCESS; + if (ha->flags.management_server_logged_in) + return ret; + + ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa, + mb, BIT_1); + if (mb[0] != MBS_COMMAND_COMPLETE) { + DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: " + "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n", + __func__, ha->host_no, ha->mgmt_svr_loop_id, mb[0], mb[1], + mb[2], mb[6], mb[7])); + ret = QLA_FUNCTION_FAILED; + } else + ha->flags.management_server_logged_in = 1; + + return ret; +} + +/** + * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + ms_iocb_entry_t *ms_pkt; + + ms_pkt = ha->ms_iocb; + memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); + + ms_pkt->entry_type = MS_IOCB_TYPE; + ms_pkt->entry_count = 1; + SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id); + ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->timeout = __constant_cpu_to_le16(59); + ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); + ms_pkt->req_bytecount = cpu_to_le32(req_size); + + ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + + ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + + return ms_pkt; +} + +/** + * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + struct ct_entry_24xx *ct_pkt; + + ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); + + ct_pkt->entry_type = CT_IOCB_TYPE; + ct_pkt->entry_count = 1; + ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); + ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + + ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + + ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + + return ct_pkt; +} + +static inline ms_iocb_entry_t * +qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size) +{ + ms_iocb_entry_t *ms_pkt = ha->ms_iocb; + struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + + if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + } else { + ms_pkt->req_bytecount = cpu_to_le32(req_size); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + } + + return ms_pkt; +} + +/** + * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. + * @ct_req: CT request buffer + * @cmd: GS command + * @rsp_size: response size in bytes + * + * Returns a pointer to the intitialized @ct_req. + */ +static inline struct ct_sns_req * +qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd, + uint16_t rsp_size) +{ + memset(ct_req, 0, sizeof(struct ct_sns_pkt)); + + ct_req->header.revision = 0x01; + ct_req->header.gs_type = 0xFA; + ct_req->header.gs_subtype = 0x10; + ct_req->command = cpu_to_be16(cmd); + ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); + + return ct_req; +} + +/** + * qla2x00_fdmi_rhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rhba(scsi_qla_host_t *ha) +{ + int rval, alen; + uint32_t size, sn; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + uint8_t *entries; + struct ct_fdmi_hba_attr *eiter; + + /* Issue RHBA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD, + RHBA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- attribute block, attributes. */ + memcpy(ct_req->req.rhba.hba_identifier, ha->port_name, WWN_SIZE); + ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1); + memcpy(ct_req->req.rhba.port_name, ha->port_name, WWN_SIZE); + size = 2 * WWN_SIZE + 4 + 4; + + /* Attributes */ + ct_req->req.rhba.attrs.count = + __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT); + entries = ct_req->req.rhba.hba_identifier; + + /* Nodename. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME); + eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE); + memcpy(eiter->a.node_name, ha->node_name, WWN_SIZE); + size += 4 + WWN_SIZE; + + DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2], + eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5], + eiter->a.node_name[6], eiter->a.node_name[7])); + + /* Manufacturer. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER); + strcpy(eiter->a.manufacturer, "QLogic Corporation"); + alen = strlen(eiter->a.manufacturer); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, ha->host_no, + eiter->a.manufacturer)); + + /* Serial number. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000); + alen = strlen(eiter->a.serial_num); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, ha->host_no, + eiter->a.serial_num)); + + /* Model name. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL); + strcpy(eiter->a.model, ha->model_number); + alen = strlen(eiter->a.model); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, ha->host_no, + eiter->a.model)); + + /* Model description. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); + if (ha->model_desc) + strncpy(eiter->a.model_desc, ha->model_desc, 80); + alen = strlen(eiter->a.model_desc); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, ha->host_no, + eiter->a.model_desc)); + + /* Hardware version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); + strcpy(eiter->a.hw_version, ha->adapter_id); + alen = strlen(eiter->a.hw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.hw_version)); + + /* Driver version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION); + strcpy(eiter->a.driver_version, qla2x00_version_str); + alen = strlen(eiter->a.driver_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, ha->host_no, + eiter->a.driver_version)); + + /* Option ROM version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); + strcpy(eiter->a.orom_version, "0.00"); + alen = strlen(eiter->a.orom_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, ha->host_no, + eiter->a.orom_version)); + + /* Firmware version */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); + ha->isp_ops.fw_version_str(ha, eiter->a.fw_version); + alen = strlen(eiter->a.fw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.fw_version)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RHBA identifier=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rhba.hba_identifier[0], + ct_req->req.rhba.hba_identifier[1], + ct_req->req.rhba.hba_identifier[2], + ct_req->req.rhba.hba_identifier[3], + ct_req->req.rhba.hba_identifier[4], + ct_req->req.rhba.hba_identifier[5], + ct_req->req.rhba.hba_identifier[6], + ct_req->req.rhba.hba_identifier[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RHBA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && + ct_rsp->header.explanation_code == + CT_EXPL_ALREADY_REGISTERED) { + DEBUG2_13(printk("%s(%ld): HBA already registered.\n", + __func__, ha->host_no)); + rval = QLA_ALREADY_REGISTERED; + } + } else { + DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_dhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_dhba(scsi_qla_host_t *ha) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RPA */ + /* Prepare common MS IOCB */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE, + DHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD, + DHBA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- portname. */ + memcpy(ct_req->req.dhba.port_name, ha->port_name, WWN_SIZE); + + DEBUG13(printk("%s(%ld): DHBA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, ha->host_no, + ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1], + ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3], + ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5], + ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7])); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "DHBA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_rpa() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rpa(scsi_qla_host_t *ha) +{ + int rval, alen; + uint32_t size, max_frame_size; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + uint8_t *entries; + struct ct_fdmi_port_attr *eiter; + struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; + + /* Issue RPA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD, + RPA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- attribute block, attributes. */ + memcpy(ct_req->req.rpa.port_name, ha->port_name, WWN_SIZE); + size = WWN_SIZE + 4; + + /* Attributes */ + ct_req->req.rpa.attrs.count = + __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); + entries = ct_req->req.rpa.port_name; + + /* FC4 types. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES); + eiter->len = __constant_cpu_to_be16(4 + 32); + eiter->a.fc4_types[2] = 0x01; + size += 4 + 32; + + DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__, ha->host_no, + eiter->a.fc4_types[2], eiter->a.fc4_types[1])); + + /* Supported speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + if (IS_QLA25XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(4); + else if (IS_QLA24XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(8); + else if (IS_QLA23XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(2); + else + eiter->a.sup_speed = __constant_cpu_to_be32(1); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.sup_speed)); + + /* Current speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + switch (ha->link_data_rate) { + case 0: + eiter->a.cur_speed = __constant_cpu_to_be32(1); + break; + case 1: + eiter->a.cur_speed = __constant_cpu_to_be32(2); + break; + case 3: + eiter->a.cur_speed = __constant_cpu_to_be32(8); + break; + case 4: + eiter->a.cur_speed = __constant_cpu_to_be32(4); + break; + } + size += 4 + 4; + + DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.cur_speed)); + + /* Max frame size. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); + eiter->len = __constant_cpu_to_be16(4 + 4); + max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ? + (uint32_t) icb24->frame_payload_size: + (uint32_t) ha->init_cb->frame_payload_size; + eiter->a.max_frame_size = cpu_to_be32(max_frame_size); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, ha->host_no, + eiter->a.max_frame_size)); + + /* OS device name. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); + sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no); + alen = strlen(eiter->a.os_dev_name); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no, + eiter->a.os_dev_name)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RPA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rpa.port_name[0], + ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2], + ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4], + ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6], + ct_req->req.rpa.port_name[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RPA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RPA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_register() - + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_fdmi_register(scsi_qla_host_t *ha) +{ + int rval; + + rval = qla2x00_mgmt_svr_login(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) { + if (rval != QLA_ALREADY_REGISTERED) + return rval; + + rval = qla2x00_fdmi_dhba(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) + return rval; + } + rval = qla2x00_fdmi_rpa(ha); + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 09b23f70fd6..e38d0cf7363 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -88,6 +88,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); rval = ha->isp_ops.pci_config(ha); @@ -2132,6 +2133,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) return (QLA_SUCCESS); } do { + /* FDMI support. */ + if (ql2xfdmienable && + test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags)) + qla2x00_fdmi_register(ha); + /* Ensure we are logged into the SNS. */ if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) loop_id = NPH_SNS; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f910de6dd43..c255bb0268a 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -451,6 +451,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->flags.management_server_logged_in = 0; ha->link_data_rate = 0; + if (ql2xfdmienable) + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); /* Update AEN queue. */ qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 774309a77c0..284eb847e50 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -252,7 +252,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) mb0 = RD_REG_WORD(®->isp24.mailbox0); ictrl = RD_REG_DWORD(®->isp24.ictrl); } else { - mb0 = RD_MAILBOX_REG(ha, reg->isp, 0); + mb0 = RD_MAILBOX_REG(ha, ®->isp, 0); ictrl = RD_REG_WORD(®->isp.ictrl); } printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n", diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 995e521b07d..0fc37d810e0 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -88,6 +88,12 @@ static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); +int ql2xfdmienable; +module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xfdmienable, + "Enables FDMI registratons " + "Default is 0 - no FDMI. 1 - perfom FDMI."); + /* * SCSI host template entry points */ @@ -1303,6 +1309,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->prev_topology = 0; ha->ports = MAX_BUSES; ha->init_cb_size = sizeof(init_cb_t); + ha->mgmt_svr_loop_id = MANAGEMENT_SERVER; /* Assign ISP specific operations. */ ha->isp_ops.pci_config = qla2100_pci_config; @@ -1325,6 +1332,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb; 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; @@ -1362,6 +1370,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->response_q_length = RESPONSE_ENTRY_CNT_2300; ha->last_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct init_cb_24xx); + ha->mgmt_svr_loop_id = 10; ha->isp_ops.pci_config = qla24xx_pci_config; ha->isp_ops.reset_chip = qla24xx_reset_chip; ha->isp_ops.chip_diag = qla24xx_chip_diag; @@ -1382,6 +1391,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.fabric_login = qla24xx_login_fabric; ha->isp_ops.fabric_logout = qla24xx_fabric_logout; ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb; 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; -- cgit v1.2.3 From f7d289f62e2ea911ecb710015efd45c687fa81ce Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:40 -0700 Subject: [SCSI] qla2xxx: Correct domain/area exclusion logic. In an FL topology, limit port recognition to those devices not within the same area and domain of the ISP. The firmware will recogonize such devices during local-loop discovery. Some devices may respond to a PLOGI before they have completed their fabric login or they may not be a public device. In this case they will report: domain == 00 area == 00 alpa == which is valid. Exclude such devices from local loop discovery. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e38d0cf7363..d12255fb938 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1900,7 +1900,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) continue; /* Bypass if not same domain and area of adapter. */ - if (area != ha->d_id.b.area || domain != ha->d_id.b.domain) + if (area && domain && + (area != ha->d_id.b.area || domain != ha->d_id.b.domain)) continue; /* Bypass invalid local loop ID. */ @@ -2400,6 +2401,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) if (new_fcport->d_id.b24 == ha->d_id.b24) continue; + /* Bypass if same domain and area of adapter. */ + if (((new_fcport->d_id.b24 & 0xffff00) == + (ha->d_id.b24 & 0xffff00)) && ha->current_topology == + ISP_CFG_FL) + continue; + /* Bypass reserved domain fields. */ if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) continue; -- cgit v1.2.3 From c00c72ae01c03d3d172150392419040f8d55ab04 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:50 -0700 Subject: [SCSI] qla2xxx: Simplify redundant target/device reset logic. Remove redundant qla2x00_target_reset() function in favour of the equivalent qla2x00_device_reset(). Update callers of old function. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 3 --- drivers/scsi/qla2xxx/qla_mbx.c | 52 ------------------------------------------ drivers/scsi/qla2xxx/qla_os.c | 2 +- 3 files changed, 1 insertion(+), 56 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3e1e5fe850a..5deaa7e6ee6 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -147,9 +147,6 @@ extern int qla2x00_abort_target(fc_port_t *); #endif -extern int -qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *); - extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, uint8_t *, uint16_t *); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 284eb847e50..953156faafd 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -983,58 +983,6 @@ qla2x00_abort_target(fc_port_t *fcport) } #endif -/* - * qla2x00_target_reset - * Issue target reset mailbox command. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);) - - if (atomic_read(&fcport->state) != FCS_ONLINE) - return 0; - - mcp->mb[0] = MBC_TARGET_RESET; - if (HAS_EXTENDED_IDS(ha)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = ha->loop_reset_delay; - mcp->out_mb = 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) { - /*EMPTY*/ - DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n", - ha->host_no, rval);) - } else { - /*EMPTY*/ - DEBUG11(printk("qla2x00_target_reset(%ld): done.\n", - ha->host_no);) - } - - return rval; -} - /* * qla2x00_get_adapter_id * Get adapter ID and topology. diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0fc37d810e0..29cf3f51093 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1022,7 +1022,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (fcport->port_type != FCT_TARGET) continue; - status = qla2x00_target_reset(ha, fcport); + status = qla2x00_device_reset(ha, fcport); if (status != QLA_SUCCESS) break; } -- cgit v1.2.3 From 06c22bd13f4eb55e291d5a31280b2ae5a70ad00d Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:00 -0700 Subject: [SCSI] qla2xxx: Correct LED scheme definition. Original implementation used an overloaded bit in the EFI parameters. The correct bit is BIT_4 of the special_options section of NVRAM. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 4 ++-- drivers/scsi/qla2xxx/qla_init.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cdef86e49c6..b7f82b757cb 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -914,7 +914,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) @@ -1036,7 +1036,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d12255fb938..c619583e646 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1564,7 +1564,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); 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->efi_parameters & BIT_3) ? 1 : 0); + ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; -- cgit v1.2.3 From c32c4cb9fbe3bdc2a90c6eaae5ae30521d4ba9fc Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:10 -0700 Subject: [SCSI] qla2xxx: Remove RISC pause/release barriers during flash manipulation. Remove unnecessary RISC pause/release barriers during ISP24xx flash manipulation. The ISP24xx can arbitrate flash access requests during RISC executions. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_sup.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index d7f5c608009..c14abf743b7 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -468,21 +468,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { uint32_t i; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ for (i = 0; i < dwords; i++, faddr++) dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, flash_data_to_access_addr(faddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return dwptr; } @@ -532,10 +523,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, ha->host_no, man_id, flash_id)); @@ -599,10 +586,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } @@ -630,11 +613,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, { uint32_t i; uint32_t *dwptr; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ dwptr = (uint32_t *)buf; @@ -642,10 +620,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, nvram_data_to_access_addr(naddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return buf; } @@ -690,10 +664,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); @@ -728,9 +698,5 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } -- cgit v1.2.3 From 131736d34ebc3251d79ddfd08a5e57a3e86decd4 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:20 -0700 Subject: [SCSI] qla2xxx: Remove redundant call to pci_unmap_sg(). In a corner-case failure where the request-q does not contain enough entries for a given request, pci_unmap_sg() would be called twice. Remove direct call and let the failure-path logic handle the unmapping. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_iocb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index ebdc3c54d15..37f82e2cd7f 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -810,12 +810,8 @@ qla24xx_start_scsi(srb_t *sp) ha->req_q_cnt = ha->request_q_length - (ha->req_ring_index - cnt); } - if (ha->req_q_cnt < (req_cnt + 2)) { - if (cmd->use_sg) - pci_unmap_sg(ha->pdev, sg, cmd->use_sg, - cmd->sc_data_direction); + if (ha->req_q_cnt < (req_cnt + 2)) goto queuing_error; - } /* Build command packet. */ ha->current_outstanding_cmd = handle; -- cgit v1.2.3 From ce7e4af7f507c156c3fd3dbb41ffe4a77c700b54 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:30 -0700 Subject: [SCSI] qla2xxx: Add change_queue_depth/type() API support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 29cf3f51093..413ccc152de 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -111,6 +111,9 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static int qla2x00_loop_reset(scsi_qla_host_t *ha); static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); +static int qla2x00_change_queue_depth(struct scsi_device *, int); +static int qla2x00_change_queue_type(struct scsi_device *, int); + static struct scsi_host_template qla2x00_driver_template = { .module = THIS_MODULE, .name = "qla2xxx", @@ -125,6 +128,8 @@ static struct scsi_host_template qla2x00_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -151,6 +156,8 @@ static struct scsi_host_template qla24xx_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -1109,6 +1116,28 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) sdev->hostdata = NULL; } +static int +qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + return sdev->queue_depth; +} + +static int +qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + /** * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context -- cgit v1.2.3 From afb046e2be724a90f21f7cf0ba50e328005bd038 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:40 -0700 Subject: [SCSI] qla2xxx: Add host attributes. Export additional host information via the shost_attrs member in the scsi_host template. Attributes include: driver version, firmware version, ISP serial number, ISP type, ISP product ID, HBA model name, HBA model description, PCI interconnect information, and HBA port state. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 132 ++++++++++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_gbl.h | 2 + drivers/scsi/qla2xxx/qla_os.c | 2 + 3 files changed, 136 insertions(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d05280eecc6..fe0fce71adc 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -211,6 +211,138 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); } +/* Scsi_Host attributes. */ + +static ssize_t +qla2x00_drvr_version_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); +} + +static ssize_t +qla2x00_fw_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char fw_str[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.fw_version_str(ha, fw_str)); +} + +static ssize_t +qla2x00_serial_num_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + uint32_t sn; + + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, + sn % 100000); +} + +static ssize_t +qla2x00_isp_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name); +} + +static ssize_t +qla2x00_isp_id_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", + ha->product_id[0], ha->product_id[1], ha->product_id[2], + ha->product_id[3]); +} + +static ssize_t +qla2x00_model_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number); +} + +static ssize_t +qla2x00_model_desc_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->model_desc ? ha->model_desc: ""); +} + +static ssize_t +qla2x00_pci_info_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char pci_info[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.pci_info_str(ha, pci_info)); +} + +static ssize_t +qla2x00_state_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + int len = 0; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN || + atomic_read(&ha->loop_state) == LOOP_DEAD) + len = snprintf(buf, PAGE_SIZE, "Link Down\n"); + else if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) + len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n"); + else { + len = snprintf(buf, PAGE_SIZE, "Link Up - "); + + switch (ha->current_topology) { + case ISP_CFG_NL: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + case ISP_CFG_FL: + len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n"); + break; + case ISP_CFG_N: + len += snprintf(buf + len, PAGE_SIZE-len, + "N_Port to N_Port\n"); + break; + case ISP_CFG_F: + len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n"); + break; + default: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + } + } + return len; +} + +static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, + NULL); +static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); +static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); +static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); +static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL); +static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL); +static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL); +static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL); +static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL); + +struct class_device_attribute *qla2x00_host_attrs[] = { + &class_device_attr_driver_version, + &class_device_attr_fw_version, + &class_device_attr_serial_num, + &class_device_attr_isp_name, + &class_device_attr_isp_id, + &class_device_attr_model_name, + &class_device_attr_model_desc, + &class_device_attr_pci_info, + &class_device_attr_state, + NULL, +}; + /* Host attributes. */ static void diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 5deaa7e6ee6..95fb0c4941a 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -290,6 +290,8 @@ extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *); /* * Global Function Prototypes in qla_attr.c source file. */ +struct class_device_attribute; +extern struct class_device_attribute *qla2x00_host_attrs[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 413ccc152de..14f2f9077c8 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -140,6 +140,7 @@ static struct scsi_host_template qla2x00_driver_template = { * which equates to 0x800000 sectors. */ .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_host_template qla24xx_driver_template = { @@ -164,6 +165,7 @@ static struct scsi_host_template qla24xx_driver_template = { .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_transport_template *qla2xxx_transport_template = NULL; -- cgit v1.2.3 From 86cd6baa8294dc5b2cedd84fb5cf3944eaf5271f Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:00 -0700 Subject: [SCSI] qla2xxx: Remove bad call to fc_remove_host() during probe failure. fc_remove_host() should only be called after a scsi_host has been successfully added via scsi_add_host() -- any failures while qla2xxx probing would result in an incorrect call to fc_remove_host() during cleanup. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 14f2f9077c8..5a542655d44 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1586,8 +1586,6 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) return 0; probe_failed: - fc_remove_host(ha->host); - qla2x00_free_device(ha); scsi_host_put(host); -- cgit v1.2.3 From fe74c71f6bb63376d92bc606597f0818f5b11c2e Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:10 -0700 Subject: [SCSI] qla2xxx: Replace schedule_timeout(). From: Nishanth Aravamudan Replace schedule_timeout() with msleep()/msleep_interruptible() as appropriate, to guarantee the task delays as expected. Signed-off-by: Nishanth Aravamudan Signed-off-by: Domen Puncer Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5a542655d44..af9b4e77cbf 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -502,14 +502,13 @@ qc24_fail_command: static int qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) { -#define ABORT_POLLING_PERIOD HZ -#define ABORT_WAIT_ITER ((10 * HZ) / (ABORT_POLLING_PERIOD)) +#define ABORT_POLLING_PERIOD 1000 +#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; while (CMD_SP(cmd)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(ABORT_POLLING_PERIOD); + msleep(ABORT_POLLING_PERIOD); if (--wait_iter) break; @@ -1960,7 +1959,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha) { struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - unsigned long wtime;/* max wait time if mbx cmd is busy. */ + unsigned int wtime;/* max wait time if mbx cmd is busy. */ if (ha == NULL) { /* error */ @@ -1969,11 +1968,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } /* Make sure all other threads are stopped. */ - wtime = 60 * HZ; - while (ha->dpc_wait && wtime) { - set_current_state(TASK_INTERRUPTIBLE); - wtime = schedule_timeout(wtime); - } + wtime = 60 * 1000; + while (ha->dpc_wait && wtime) + wtime = msleep_interruptible(wtime); /* free ioctl memory */ qla2x00_free_ioctl_mem(ha); @@ -2504,15 +2501,15 @@ qla2x00_timer(scsi_qla_host_t *ha) int qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) { - const unsigned int step = HZ/10; + const unsigned int step = 100; /* msecs */ + unsigned int iterations = jiffies_to_msecs(timeout)/100; do { if (!down_trylock(sema)) return 0; - set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(step)) + if (msleep_interruptible(step)) break; - } while ((timeout -= step) > 0); + } while (--iterations >= 0); return -ETIMEDOUT; } -- cgit v1.2.3 From f6ef3b1872915c6d69ca36cf4ca16269cb9a73ad Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:20 -0700 Subject: [SCSI] qla2xxx: Stop firmware execution at unintialization time. On ISP24xx parts, stop execution of firmware during ISP tear-down. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_gbl.h | 3 +++ drivers/scsi/qla2xxx/qla_mbx.c | 29 +++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_os.c | 14 ++++++++------ 4 files changed, 41 insertions(+), 6 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b7f82b757cb..b455c31405e 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -631,6 +631,7 @@ typedef struct { #define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ #define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */ #define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */ +#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */ #define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ #define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ #define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 95fb0c4941a..1ed32e7b547 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -213,6 +213,9 @@ qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *, extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); +extern int +qla2x00_stop_firmware(scsi_qla_host_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 953156faafd..13e1c904707 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2427,3 +2427,32 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g, return rval; } + +int +qla2x00_stop_firmware(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_STOP_FIRMWARE; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 5; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } 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 af9b4e77cbf..8982978c42f 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -79,7 +79,7 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); -int ql2xfwloadbin; +int ql2xfwloadbin=1; module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xfwloadbin, "Load ISP2xxx firmware image via hotplug."); @@ -1626,10 +1626,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) qla2x00_cancel_io_descriptors(ha); - /* turn-off interrupts on the card */ - if (ha->interrupts_on) - ha->isp_ops.disable_intrs(ha); - /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); @@ -1649,8 +1645,14 @@ qla2x00_free_device(scsi_qla_host_t *ha) } } - qla2x00_mem_free(ha); + /* Stop currently executing firmware. */ + qla2x00_stop_firmware(ha); + /* turn-off interrupts on the card */ + if (ha->interrupts_on) + ha->isp_ops.disable_intrs(ha); + + qla2x00_mem_free(ha); ha->flags.online = 0; -- cgit v1.2.3 From 1aab60c25e9a500b9f15c1dfd775e70e7bde555c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:30 -0700 Subject: [SCSI] qla2xxx: Update version number to 8.01.00-k. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e3cd3618bc5..eae7d6edd53 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -19,9 +19,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.00b5-k" +#define QLA2XXX_VERSION "8.01.00-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 5 +#define QLA_DRIVER_BETA_VER 0 -- cgit v1.2.3 From 4dddbc26c3895ecdab1f4b16435685b47f96f599 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 6 Sep 2005 17:11:54 -0500 Subject: [SCSI] ibmvscsi: handle large scatter/gather lists The maximum size of a scatter-gather list that the current IBM VSCSI Client can handle is 10. This patch adds large scatter-gather support to the client so that it is capable of handling up to SG_ALL(255) number of requests in the scatter-gather list. Signed-off-by: Linda Xie Acked by: Dave C Boutcher Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 156 ++++++++++++++++++++++++++++----------- drivers/scsi/ibmvscsi/ibmvscsi.h | 2 + 2 files changed, 116 insertions(+), 42 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e3e6752c410..1b911dadf64 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -87,7 +87,7 @@ static int max_channel = 3; static int init_timeout = 5; static int max_requests = 50; -#define IBMVSCSI_VERSION "1.5.6" +#define IBMVSCSI_VERSION "1.5.7" MODULE_DESCRIPTION("IBM Virtual SCSI"); MODULE_AUTHOR("Dave Boutcher"); @@ -145,6 +145,8 @@ static int initialize_event_pool(struct event_pool *pool, sizeof(*evt->xfer_iu) * i; evt->xfer_iu = pool->iu_storage + i; evt->hostdata = hostdata; + evt->ext_list = NULL; + evt->ext_list_token = 0; } return 0; @@ -161,9 +163,16 @@ static void release_event_pool(struct event_pool *pool, struct ibmvscsi_host_data *hostdata) { int i, in_use = 0; - for (i = 0; i < pool->size; ++i) + for (i = 0; i < pool->size; ++i) { if (atomic_read(&pool->events[i].free) != 1) ++in_use; + if (pool->events[i].ext_list) { + dma_free_coherent(hostdata->dev, + SG_ALL * sizeof(struct memory_descriptor), + pool->events[i].ext_list, + pool->events[i].ext_list_token); + } + } if (in_use) printk(KERN_WARNING "ibmvscsi: releasing event pool with %d " @@ -286,24 +295,41 @@ static void set_srp_direction(struct scsi_cmnd *cmd, } else { if (cmd->sc_data_direction == DMA_TO_DEVICE) { srp_cmd->data_out_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_out_count = numbuf; + srp_cmd->data_out_count = + numbuf < MAX_INDIRECT_BUFS ? + numbuf: MAX_INDIRECT_BUFS; } else { srp_cmd->data_in_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_in_count = numbuf; + srp_cmd->data_in_count = + numbuf < MAX_INDIRECT_BUFS ? + numbuf: MAX_INDIRECT_BUFS; } } } +static void unmap_sg_list(int num_entries, + struct device *dev, + struct memory_descriptor *md) +{ + int i; + + for (i = 0; i < num_entries; ++i) { + dma_unmap_single(dev, + md[i].virtual_address, + md[i].length, DMA_BIDIRECTIONAL); + } +} + /** * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format * @cmd: srp_cmd whose additional_data member will be unmapped * @dev: device for which the memory is mapped * */ -static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) +static void unmap_cmd_data(struct srp_cmd *cmd, + struct srp_event_struct *evt_struct, + struct device *dev) { - int i; - if ((cmd->data_out_format == SRP_NO_BUFFER) && (cmd->data_in_format == SRP_NO_BUFFER)) return; @@ -318,15 +344,34 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) (struct indirect_descriptor *)cmd->additional_data; int num_mapped = indirect->head.length / sizeof(indirect->list[0]); - for (i = 0; i < num_mapped; ++i) { - struct memory_descriptor *data = &indirect->list[i]; - dma_unmap_single(dev, - data->virtual_address, - data->length, DMA_BIDIRECTIONAL); + + if (num_mapped <= MAX_INDIRECT_BUFS) { + unmap_sg_list(num_mapped, dev, &indirect->list[0]); + return; } + + unmap_sg_list(num_mapped, dev, evt_struct->ext_list); } } +static int map_sg_list(int num_entries, + struct scatterlist *sg, + struct memory_descriptor *md) +{ + int i; + u64 total_length = 0; + + for (i = 0; i < num_entries; ++i) { + struct memory_descriptor *descr = md + i; + struct scatterlist *sg_entry = &sg[i]; + descr->virtual_address = sg_dma_address(sg_entry); + descr->length = sg_dma_len(sg_entry); + descr->memory_handle = 0; + total_length += sg_dma_len(sg_entry); + } + return total_length; +} + /** * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields * @cmd: Scsi_Cmnd with the scatterlist @@ -337,10 +382,11 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) * Returns 1 on success. */ static int map_sg_data(struct scsi_cmnd *cmd, + struct srp_event_struct *evt_struct, struct srp_cmd *srp_cmd, struct device *dev) { - int i, sg_mapped; + int sg_mapped; u64 total_length = 0; struct scatterlist *sg = cmd->request_buffer; struct memory_descriptor *data = @@ -363,27 +409,46 @@ static int map_sg_data(struct scsi_cmnd *cmd, return 1; } - if (sg_mapped > MAX_INDIRECT_BUFS) { + if (sg_mapped > SG_ALL) { printk(KERN_ERR "ibmvscsi: More than %d mapped sg entries, got %d\n", - MAX_INDIRECT_BUFS, sg_mapped); + SG_ALL, sg_mapped); return 0; } indirect->head.virtual_address = 0; indirect->head.length = sg_mapped * sizeof(indirect->list[0]); indirect->head.memory_handle = 0; - for (i = 0; i < sg_mapped; ++i) { - struct memory_descriptor *descr = &indirect->list[i]; - struct scatterlist *sg_entry = &sg[i]; - descr->virtual_address = sg_dma_address(sg_entry); - descr->length = sg_dma_len(sg_entry); - descr->memory_handle = 0; - total_length += sg_dma_len(sg_entry); + + if (sg_mapped <= MAX_INDIRECT_BUFS) { + total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]); + indirect->total_length = total_length; + return 1; } - indirect->total_length = total_length; - return 1; + /* get indirect table */ + if (!evt_struct->ext_list) { + evt_struct->ext_list =(struct memory_descriptor*) + dma_alloc_coherent(dev, + SG_ALL * sizeof(struct memory_descriptor), + &evt_struct->ext_list_token, 0); + if (!evt_struct->ext_list) { + printk(KERN_ERR + "ibmvscsi: Can't allocate memory for indirect table\n"); + return 0; + + } + } + + total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list); + + indirect->total_length = total_length; + indirect->head.virtual_address = evt_struct->ext_list_token; + indirect->head.length = sg_mapped * sizeof(indirect->list[0]); + memcpy(indirect->list, evt_struct->ext_list, + MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor)); + + return 1; } /** @@ -428,6 +493,7 @@ static int map_single_data(struct scsi_cmnd *cmd, * Returns 1 on success. */ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, + struct srp_event_struct *evt_struct, struct srp_cmd *srp_cmd, struct device *dev) { switch (cmd->sc_data_direction) { @@ -450,7 +516,7 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, if (!cmd->request_buffer) return 1; if (cmd->use_sg) - return map_sg_data(cmd, srp_cmd, dev); + return map_sg_data(cmd, evt_struct, srp_cmd, dev); return map_single_data(cmd, srp_cmd, dev); } @@ -486,6 +552,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, printk(KERN_WARNING "ibmvscsi: Warning, request_limit exceeded\n"); unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; @@ -513,7 +580,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, return 0; send_error: - unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev); + unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); if ((cmnd = evt_struct->cmnd) != NULL) { cmnd->result = DID_ERROR << 16; @@ -551,6 +618,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct) rsp->sense_and_response_data, rsp->sense_data_list_length); unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct, evt_struct->hostdata->dev); if (rsp->doover) @@ -583,6 +651,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, { struct srp_cmd *srp_cmd; struct srp_event_struct *evt_struct; + struct indirect_descriptor *indirect; struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; u16 lun = lun_from_dev(cmnd->device); @@ -591,14 +660,6 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, if (!evt_struct) return SCSI_MLQUEUE_HOST_BUSY; - init_event_struct(evt_struct, - handle_cmd_rsp, - VIOSRP_SRP_FORMAT, - cmnd->timeout_per_command/HZ); - - evt_struct->cmnd = cmnd; - evt_struct->cmnd_done = done; - /* Set up the actual SRP IU */ srp_cmd = &evt_struct->iu.srp.cmd; memset(srp_cmd, 0x00, sizeof(*srp_cmd)); @@ -606,17 +667,25 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); srp_cmd->lun = ((u64) lun) << 48; - if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) { + if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) { printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; } + init_event_struct(evt_struct, + handle_cmd_rsp, + VIOSRP_SRP_FORMAT, + cmnd->timeout_per_command/HZ); + + evt_struct->cmnd = cmnd; + evt_struct->cmnd_done = done; + /* Fix up dma address of the buffer itself */ - if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || - (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) { - struct indirect_descriptor *indirect = - (struct indirect_descriptor *)srp_cmd->additional_data; + indirect = (struct indirect_descriptor *)srp_cmd->additional_data; + if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || + (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) && + (indirect->head.virtual_address == 0)) { indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + offsetof(struct srp_cmd, additional_data) + offsetof(struct indirect_descriptor, list); @@ -931,7 +1000,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) cmd->result = (DID_ABORT << 16); list_del(&found_evt->list); - unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); + unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt, + found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); spin_unlock_irqrestore(hostdata->host->host_lock, flags); atomic_inc(&hostdata->request_limit); @@ -1023,7 +1093,8 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) if (tmp_evt->cmnd) tmp_evt->cmnd->result = (DID_RESET << 16); list_del(&tmp_evt->list); - unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt, + tmp_evt->hostdata->dev); free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); atomic_inc(&hostdata->request_limit); @@ -1052,6 +1123,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata) if (tmp_evt->cmnd) { tmp_evt->cmnd->result = (DID_ERROR << 16); unmap_cmd_data(&tmp_evt->iu.srp.cmd, + tmp_evt, tmp_evt->hostdata->dev); if (tmp_evt->cmnd_done) tmp_evt->cmnd_done(tmp_evt->cmnd); @@ -1356,7 +1428,7 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 16, .can_queue = 1, /* Updated after SRP_LOGIN */ .this_id = -1, - .sg_tablesize = MAX_INDIRECT_BUFS, + .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvscsi_attrs, }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 1030b703c30..8bec0438dc8 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -68,6 +68,8 @@ struct srp_event_struct { void (*cmnd_done) (struct scsi_cmnd *); struct completion comp; union viosrp_iu *sync_srp; + struct memory_descriptor *ext_list; + dma_addr_t ext_list_token; }; /* a pool of event structs for use */ -- cgit v1.2.3 From e47373ec1c9aab9ee134f4e2b8249957e9f4c7ef Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Mar 2005 15:05:45 -0500 Subject: [SCSI] return success after retries in scsi_eh_tur The problem lies in the way the error handler uses TEST UNIT READY to tell whether error recovery has succeeded. The scsi_eh_tur function gives up after one round of retrying; after that it decides that more error recovery is needed. However TUR is liable to report sense data indicating a retry is needed when in fact error recovery has succeeded. A typical example might be SK=2, ASC=4, ASCQ=1 (Logical unit in process of becoming ready). The mere fact that we were able to get a sensible reply to the TUR should indicate that the device is working well enough to stop error recovery. I ran across a case back in January where this happened. A CD-ROM drive timed out the INQUIRY command, and a device reset fixed the blockage. But then the drive kept responding with 2/4/1 -- because it was spinning up I suppose -- until the error handler gave up and placed it offline. If the initial INQUIRY had received the 2/4/1 instead, everything would have worked okay. It doesn't seem reasonable for things to fail just because the error handler had started running. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e9c451ba71f..688bce74078 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -776,9 +776,11 @@ retry_tur: __FUNCTION__, scmd, rtn)); if (rtn == SUCCESS) return 0; - else if (rtn == NEEDS_RETRY) + else if (rtn == NEEDS_RETRY) { if (retry_cnt--) goto retry_tur; + return 0; + } return 1; } -- cgit v1.2.3 From 4451e472627881e3e2240b224f127c99be500f91 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 12 Jul 2005 10:45:17 -0400 Subject: [SCSI] sd: pause in sd_spinup_disk for slow USB devices This patch adds a delay tailored for USB flash devices that are slow to initialize their firmware. The symptom is a repeated Unit Attention with ASC=0x28 (Not Ready to Ready transition). The patch will wait for up to 5 seconds for such devices to become ready. Normal devices won't send the repeated Unit Attention sense key and hence won't trigger the patch. This fixes a problem with James Roberts-Thomson's USB device, and I've seen several reports of other devices exhibiting the same symptoms -- presumably they will be helped as well. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0410e1bf109..41ba0809f79 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -984,7 +984,7 @@ static void sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { unsigned char cmd[10]; - unsigned long spintime_value = 0; + unsigned long spintime_expire = 0; int retries, spintime; unsigned int the_result; struct scsi_sense_hdr sshdr; @@ -1071,12 +1071,27 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, scsi_wait_req(SRpnt, (void *)cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); - spintime_value = jiffies; + spintime_expire = jiffies + 100 * HZ; + spintime = 1; } - spintime = 1; /* Wait 1 second for next try */ msleep(1000); printk("."); + + /* + * Wait for USB flash devices with slow firmware. + * Yes, this sense key/ASC combination shouldn't + * occur here. It's characteristic of these devices. + */ + } else if (sense_valid && + sshdr.sense_key == UNIT_ATTENTION && + sshdr.asc == 0x28) { + if (!spintime) { + spintime_expire = jiffies + 5 * HZ; + spintime = 1; + } + /* Wait 1 second for next try */ + msleep(1000); } else { /* we don't understand the sense code, so it's * probably pointless to loop */ @@ -1088,8 +1103,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, break; } - } while (spintime && - time_after(spintime_value + 100 * HZ, jiffies)); + } while (spintime && time_before_eq(jiffies, spintime_expire)); if (spintime) { if (scsi_status_is_good(the_result)) -- cgit v1.2.3 From 4869040512082b761de2d7c35975d01044f8bfea Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 6 Sep 2005 18:08:14 +1000 Subject: [SCSI] Universal Xport no attach blacklist On Fri, Dec 13, 2002 at 12:24:39AM +1100, Anton Blanchard wrote: > We tested 2.5.51 on a ppc64 box, qlogic 2312 and a fastt700 array. I > had CONFIG_SCSI_REPORT_LUNS and unfortunately it thought the management > LUN was a disk: > > Vendor: IBM Model: Universal Xport Rev: 0520 > Type: Direct-Access ANSI SCSI revision: 03 > > ... > > SCSI device sdaj: drive cache: write through > SCSI device sdaj: 40960 512-byte hdwr sectors (21 MB) > sdaj: unknown partition table > Attached scsi disk sdaj at scsi2, channel 0, id 0, lun 31 > > ... > > end_request: I/O error, dev sdaj, sector 0 Three years later... It looks like SGI use the same FC vendor and they already have a workaround for this issue. The following patch adds the IBM version of it. Signed-off-by: Anton Blanchard Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b444ec2e1c6..07b554affcf 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -192,6 +192,7 @@ static struct { {"SGI", "RAID5", "*", BLIST_SPARSELUN}, {"SGI", "TP9100", "*", BLIST_REPORTLUN2}, {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, + {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ -- cgit v1.2.3 From 32993523dc59759ae6cb349e4d231d4cd2165329 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:03:44 +0200 Subject: [SCSI] fix SCSI_IOCTL_PROBE_HOST This returns always false with new-style drivers right now. Make it return always true instead, as a host must be present if we are able to call the ioctl (without a host attached there would be no device node to call on..) Signed-off-by: James Bottomley --- drivers/scsi/scsi_ioctl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index f5bf5c07be9..946c31fa646 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -30,20 +30,20 @@ #define MAX_BUF PAGE_SIZE -/* - * If we are told to probe a host, we will return 0 if the host is not - * present, 1 if the host is present, and will return an identifying - * string at *arg, if arg is non null, filling to the length stored at - * (int *) arg +/** + * ioctl_probe -- return host identification + * @host: host to identify + * @buffer: userspace buffer for identification + * + * Return an identifying string at @buffer, if @buffer is non-NULL, filling + * to the length stored at * (int *) @buffer. */ - static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) { unsigned int len, slen; const char *string; - int temp = host->hostt->present; - if (temp && buffer) { + if (buffer) { if (get_user(len, (unsigned int __user *) buffer)) return -EFAULT; @@ -59,7 +59,7 @@ static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) return -EFAULT; } } - return temp; + return 1; } /* -- cgit v1.2.3 From c5478def7a3a2dba9ceda452c2aa3539514d30a9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:04:26 +0200 Subject: [SCSI] switch EH thread startup to the kthread API Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 23 ++++++++--------------- drivers/scsi/scsi_error.c | 29 ++--------------------------- 2 files changed, 10 insertions(+), 42 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8640ad1c17e..85503fad789 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -225,15 +226,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; - if (shost->ehandler) { - DECLARE_COMPLETION(sem); - shost->eh_notify = &sem; - shost->eh_kill = 1; - up(shost->eh_wait); - wait_for_completion(&sem); - shost->eh_notify = NULL; - } - + if (shost->ehandler) + kthread_stop(shost->ehandler); if (shost->work_q) destroy_workqueue(shost->work_q); @@ -263,7 +257,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; int gfp_mask = GFP_KERNEL, rval; - DECLARE_COMPLETION(complete); if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; @@ -369,12 +362,12 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d", shost->host_no); - shost->eh_notify = &complete; - rval = kernel_thread(scsi_error_handler, shost, 0); - if (rval < 0) + shost->ehandler = kthread_run(scsi_error_handler, shost, + "scsi_eh_%d", shost->host_no); + if (IS_ERR(shost->ehandler)) { + rval = PTR_ERR(shost->ehandler); goto fail_destroy_freelist; - wait_for_completion(&complete); - shost->eh_notify = NULL; + } scsi_proc_hostdir_add(shost->hostt); return shost; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 688bce74078..ebe74ccb518 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1585,16 +1586,8 @@ int scsi_error_handler(void *data) int rtn; DECLARE_MUTEX_LOCKED(sem); - /* - * Flush resources - */ - - daemonize("scsi_eh_%d", shost->host_no); - current->flags |= PF_NOFREEZE; - shost->eh_wait = &sem; - shost->ehandler = current; /* * Wake up the thread that created us. @@ -1602,8 +1595,6 @@ int scsi_error_handler(void *data) SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of" " scsi_eh_%d\n",shost->host_no)); - complete(shost->eh_notify); - while (1) { /* * If we get a signal, it means we are supposed to go @@ -1624,7 +1615,7 @@ int scsi_error_handler(void *data) * semaphores isn't unreasonable. */ down_interruptible(&sem); - if (shost->eh_kill) + if (kthread_should_stop()) break; SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" @@ -1663,22 +1654,6 @@ int scsi_error_handler(void *data) * Make sure that nobody tries to wake us up again. */ shost->eh_wait = NULL; - - /* - * Knock this down too. From this point on, the host is flying - * without a pilot. If this is because the module is being unloaded, - * that's fine. If the user sent a signal to this thing, we are - * potentially in real danger. - */ - shost->eh_active = 0; - shost->ehandler = NULL; - - /* - * If anyone is waiting for us to exit (i.e. someone trying to unload - * a driver), then wake up that process to let them know we are on - * the way out the door. - */ - complete_and_exit(shost->eh_notify, 0); return 0; } -- cgit v1.2.3 From fe1b2d544d71300f8e2d151c3c77a130d13a58be Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:15:37 +0200 Subject: [SCSI] unexport scsi_add_timer/scsi_delete_timer Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 2 -- drivers/scsi/scsi_priv.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ebe74ccb518..ae28bcb7924 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -116,7 +116,6 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, add_timer(&scmd->eh_timeout); } -EXPORT_SYMBOL(scsi_add_timer); /** * scsi_delete_timer - Delete/cancel timer for a given function. @@ -144,7 +143,6 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) return rtn; } -EXPORT_SYMBOL(scsi_delete_timer); /** * scsi_times_out - Timeout function for normal scsi commands. diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index d30d7f4e63e..ee6de1768e5 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -63,6 +63,9 @@ extern int __init scsi_init_devinfo(void); extern void scsi_exit_devinfo(void); /* scsi_error.c */ +extern void scsi_add_timer(struct scsi_cmnd *, int, + void (*)(struct scsi_cmnd *)); +extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_times_out(struct scsi_cmnd *cmd); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); -- cgit v1.2.3 From 3173d8c342971a03857d8af749a3f57da7d06b57 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 4 Sep 2005 11:32:05 -0500 Subject: [SCSI] quieten messages on scsi_execute commands scsi_io_completion() can be a bit noisy about certain conditions. Previously this wasn't a problem for internally generated commands, since they never hit it. However, since we do all SCSI commands via bios, now they do. user CD testers like magicdev are now getting not ready messages every time they touch the CD to see if there's anything in it. Fix this by making all scsi_execute commands REQ_QUIET and making scsi_finish_io() not say anything for REQ_QUIET. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) (limited to 'drivers/scsi') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 72a47ce7a1d..77f2d444f7e 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -315,7 +315,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req->sense = sense; req->sense_len = 0; req->timeout = timeout; - req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL; + req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET; /* * head injection *required* here otherwise quiesce won't work @@ -927,17 +927,20 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, scsi_requeue_command(q, cmd); return; } - printk(KERN_INFO "Device %s not ready.\n", - req->rq_disk ? req->rq_disk->disk_name : ""); + if (!(req->flags & REQ_QUIET)) + dev_printk(KERN_INFO, + &cmd->device->sdev_gendev, + "Device not ready.\n"); cmd = scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: - printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ", - cmd->device->host->host_no, - (int)cmd->device->channel, - (int)cmd->device->id, (int)cmd->device->lun); - __scsi_print_command(cmd->data_cmnd); - scsi_print_sense("", cmd); + if (!(req->flags & REQ_QUIET)) { + dev_printk(KERN_INFO, + &cmd->device->sdev_gendev, + "Volume overflow, CDB: "); + __scsi_print_command(cmd->data_cmnd); + scsi_print_sense("", cmd); + } cmd = scsi_end_request(cmd, 0, block_bytes, 1); return; default: @@ -954,15 +957,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, return; } if (result) { - if (!(req->flags & REQ_SPECIAL)) - printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " - "= 0x%x\n", cmd->device->host->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, result); - - if (driver_byte(result) & DRIVER_SENSE) - scsi_print_sense("", cmd); + if (!(req->flags & REQ_QUIET)) { + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, + "SCSI error: return code = 0x%x\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 -- cgit v1.2.3