STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
+static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
+static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
STATIC struct device_attribute *NCR_700_dev_attrs[];
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
- return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp),
- spi_period(SDp));
+ return NCR_700_offset_period_to_sxfer(hostdata,
+ spi_offset(SDp->sdev_target),
+ spi_period(SDp->sdev_target));
}
struct Scsi_Host *
NCR_700_detect(struct scsi_host_template *tpnt,
- struct NCR_700_Host_Parameters *hostdata)
+ struct NCR_700_Host_Parameters *hostdata, struct device *dev,
+ unsigned long irq, u8 scsi_id)
{
dma_addr_t pScript, pSlots;
__u8 *memory;
* if this isn't sufficient separation to avoid dma flushing issues */
BUG_ON(!dma_is_consistent(pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());
hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
+ hostdata->dev = dev;
pSlots = pScript + SLOTS_OFFSET;
tpnt->use_clustering = ENABLE_CLUSTERING;
tpnt->slave_configure = NCR_700_slave_configure;
tpnt->slave_destroy = NCR_700_slave_destroy;
+ tpnt->change_queue_depth = NCR_700_change_queue_depth;
+ tpnt->change_queue_type = NCR_700_change_queue_type;
if(tpnt->name == NULL)
tpnt->name = "53c700";
host->unique_id = hostdata->base;
host->base = hostdata->base;
hostdata->eh_complete = NULL;
+ host->irq = irq;
+ host->this_id = scsi_id;
host->hostdata[0] = (unsigned long)hostdata;
/* kick the chip */
NCR_700_writeb(0xff, host, CTEST9_REG);
/* reset the chip */
NCR_700_chip_reset(host);
+ if (request_irq(irq, NCR_700_intr, SA_SHIRQ, dev->bus_id, host)) {
+ dev_printk(KERN_ERR, dev, "53c700: irq %lu request failed\n ",
+ irq);
+ goto out_put_host;
+ }
+
+ if (scsi_add_host(host, dev)) {
+ dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n");
+ goto out_release_irq;
+ }
+
+ spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
+ SPI_SIGNAL_SE;
+
return host;
+
+ out_release_irq:
+ free_irq(irq, host);
+ out_put_host:
+ scsi_host_put(host);
+
+ return NULL;
}
int
}
if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
- if(spi_offset(SCp->device) != 0)
+ if(spi_offset(SCp->device->sdev_target) != 0)
printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
host->host_no, pun, lun,
offset, period*4);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
}
- spi_offset(SCp->device) = offset;
- spi_period(SCp->device) = period;
+ spi_offset(SCp->device->sdev_target) = offset;
+ spi_period(SCp->device->sdev_target) = period;
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
case A_REJECT_MSG:
if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
/* Rejected our sync negotiation attempt */
- spi_period(SCp->device) = spi_offset(SCp->device) = 0;
+ spi_period(SCp->device->sdev_target) =
+ spi_offset(SCp->device->sdev_target) = 0;
NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
- } else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
+ } else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) {
/* rejected our first simple tag message */
printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
- NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* we're done negotiating */
+ NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
hostdata->tag_negotiated &= ~(1<<SCp->device->id);
SCp->device->tagged_supported = 0;
scsi_deactivate_tcq(SCp->device, host->cmd_per_lun);
if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
DEBUG((" COMMAND COMPLETE, status=%02x\n",
hostdata->status[0]));
- /* OK, if TCQ still on, we know it works */
- NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ /* OK, if TCQ still under negotiation, we now know it works */
+ if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION)
+ NCR_700_set_tag_neg_state(SCp->device,
+ NCR_700_FINISHED_TAG_NEGOTIATION);
+
/* check for contingent allegiance contitions */
if(status_byte(hostdata->status[0]) == CHECK_CONDITION ||
status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
sizeof(NCR_700_SDTR_msg));
- hostdata->msgout[count+3] = spi_period(SCp->device);
- hostdata->msgout[count+4] = spi_offset(SCp->device);
+ hostdata->msgout[count+3] = spi_period(SCp->device->sdev_target);
+ hostdata->msgout[count+4] = spi_offset(SCp->device->sdev_target);
count += sizeof(NCR_700_SDTR_msg);
NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
}
printk("53c700: scsi%d, command ", SCp->device->host->host_no);
scsi_print_command(SCp);
#endif
- if(SCp->device->tagged_supported && !SCp->device->simple_tags
- && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
- && NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
- /* upper layer has indicated tags are supported. We don't
- * necessarily believe it yet.
- *
- * NOTE: There is a danger here: the mid layer supports
- * tag queuing per LUN. We only support it per PUN because
- * of potential reselection issues */
- scsi_activate_tcq(SCp->device, NCR_700_DEFAULT_TAGS);
- }
-
if(blk_rq_tagged(SCp->request)
- && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0) {
- printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+ && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
+ && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
+ printk(KERN_ERR "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
hostdata->tag_negotiated |= (1<<SCp->device->id);
- NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+ NCR_700_set_tag_neg_state(SCp->device, NCR_700_DURING_TAG_NEGOTIATION);
}
/* here we may have to process an untagged command. The gate
hostdata->tag_negotiated &= ~(1<<SCp->device->id);
}
- if((hostdata->tag_negotiated &(1<<SCp->device->id))) {
+ if((hostdata->tag_negotiated &(1<<SCp->device->id))
+ && scsi_get_tag_type(SCp->device)) {
slot->tag = SCp->request->tag;
DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n",
SCp->device->host->host_no, SCp->device->id, SCp->device->lun, slot->tag,
* reset via sg or something */
while(hostdata->eh_complete != NULL) {
spin_unlock_irq(SCp->device->host->host_lock);
- schedule_timeout(HZ/10);
+ msleep_interruptible(100);
spin_lock_irq(SCp->device->host->host_lock);
}
hostdata->eh_complete = &complete;
}
STATIC void
-NCR_700_set_period(struct scsi_device *SDp, int period)
+NCR_700_set_period(struct scsi_target *STp, int period)
{
+ struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
struct NCR_700_Host_Parameters *hostdata =
- (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+ (struct NCR_700_Host_Parameters *)SHp->hostdata[0];
if(!hostdata->fast)
return;
if(period < hostdata->min_period)
period = hostdata->min_period;
- spi_period(SDp) = period;
- NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
- NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
- NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+ spi_period(STp) = period;
+ spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+ NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
}
STATIC void
-NCR_700_set_offset(struct scsi_device *SDp, int offset)
+NCR_700_set_offset(struct scsi_target *STp, int offset)
{
+ struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
struct NCR_700_Host_Parameters *hostdata =
- (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+ (struct NCR_700_Host_Parameters *)SHp->hostdata[0];
int max_offset = hostdata->chip710
? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET;
offset = max_offset;
/* if we're currently async, make sure the period is reasonable */
- if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period ||
- spi_period(SDp) > 0xff))
- spi_period(SDp) = hostdata->min_period;
-
- spi_offset(SDp) = offset;
- NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
- NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
- NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+ if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period ||
+ spi_period(STp) > 0xff))
+ spi_period(STp) = hostdata->min_period;
+
+ spi_offset(STp) = offset;
+ spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+ NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+ spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
}
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
- /* do TCQ stuff here */
+ scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
+ scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS);
+ NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
} else {
/* initialise to default depth */
scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
}
if(hostdata->fast) {
/* Find the correct offset and period via domain validation */
- spi_dv_device(SDp);
+ if (!spi_initial_dv(SDp->sdev_target))
+ spi_dv_device(SDp);
} else {
- spi_offset(SDp) = 0;
- spi_period(SDp) = 0;
+ spi_offset(SDp->sdev_target) = 0;
+ spi_period(SDp->sdev_target) = 0;
}
return 0;
}
/* to do here: deallocate memory */
}
-static ssize_t
-NCR_700_store_queue_depth(struct device *dev, const char *buf, size_t count)
+static int
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
{
- int depth;
+ if (depth > NCR_700_MAX_TAGS)
+ depth = NCR_700_MAX_TAGS;
- struct scsi_device *SDp = to_scsi_device(dev);
- depth = simple_strtoul(buf, NULL, 0);
- if(depth > NCR_700_MAX_TAGS)
- return -EINVAL;
- scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, depth);
+ scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth);
+ return depth;
+}
- return count;
+static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
+{
+ int change_tag = ((tag_type ==0 && scsi_get_tag_type(SDp) != 0)
+ || (tag_type != 0 && scsi_get_tag_type(SDp) == 0));
+ struct NCR_700_Host_Parameters *hostdata =
+ (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+ scsi_set_tag_type(SDp, tag_type);
+
+ /* We have a global (per target) flag to track whether TCQ is
+ * enabled, so we'll be turning it off for the entire target here.
+ * our tag algorithm will fail if we mix tagged and untagged commands,
+ * so quiesce the device before doing this */
+ if (change_tag)
+ scsi_target_quiesce(SDp->sdev_target);
+
+ if (!tag_type) {
+ /* shift back to the default unqueued number of commands
+ * (the user can still raise this) */
+ scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun);
+ hostdata->tag_negotiated &= ~(1 << SDp->id);
+ } else {
+ /* Here, we cleared the negotiation flag above, so this
+ * will force the driver to renegotiate */
+ scsi_activate_tcq(SDp, SDp->queue_depth);
+ if (change_tag)
+ NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
+ }
+ if (change_tag)
+ scsi_target_resume(SDp->sdev_target);
+
+ return tag_type;
}
static ssize_t
return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
}
-static struct device_attribute NCR_700_queue_depth_attr = {
- .attr = {
- .name = "queue_depth",
- .mode = S_IWUSR,
- },
- .store = NCR_700_store_queue_depth,
-};
-
static struct device_attribute NCR_700_active_tags_attr = {
.attr = {
.name = "active_tags",
};
STATIC struct device_attribute *NCR_700_dev_attrs[] = {
- &NCR_700_queue_depth_attr,
&NCR_700_active_tags_attr,
NULL,
};