📄 i2o_scsi.c
字号:
/* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * Complications for I2O scsi * * o Each (bus,lun) is a logical device in I2O. We keep a map * table. We spoof failed selection for unmapped units * o Request sense buffers can come back for free. * o Scatter gather is a bit dynamic. We have to investigate at * setup time. * o Some of our resources are dynamically shared. The i2o core * needs a message reservation protocol to avoid swap v net * deadlocking. We need to back off queue requests. * * In general the firmware wants to help. Where its help isn't performance * useful we just ignore the aid. Its not worth the code in truth. * * Fixes: * Steve Ralston : Scatter gather now works * * To Do * 64bit cleanups * Fix the resource management problems. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <linux/prefetch.h>#include <asm/dma.h>#include <asm/system.h>#include <asm/io.h>#include <asm/atomic.h>#include <linux/blk.h>#include <linux/version.h>#include <linux/i2o.h>#include "../../scsi/scsi.h"#include "../../scsi/hosts.h"#include "../../scsi/sd.h"#include "i2o_scsi.h"#define VERSION_STRING "Version 0.0.1"#define dprintk(x)#define MAXHOSTS 32struct i2o_scsi_host{ struct i2o_controller *controller; s16 task[16][8]; /* Allow 16 devices for now */ unsigned long tagclock[16][8]; /* Tag clock for queueing */ s16 bus_task; /* The adapter TID */};static int scsi_context;static int lun_done;static int i2o_scsi_hosts;static u32 *retry[32];static struct i2o_controller *retry_ctrl[32];static struct timer_list retry_timer;static int retry_ct = 0;static atomic_t queue_depth;/* * SG Chain buffer support... */#define SG_MAX_FRAGS 64/* * FIXME: we should allocate one of these per bus we find as we * locate them not in a lump at boot. */ typedef struct _chain_buf{ u32 sg_flags_cnt[SG_MAX_FRAGS]; u32 sg_buf[SG_MAX_FRAGS];} chain_buf;#define SG_CHAIN_BUF_SZ sizeof(chain_buf)#define SG_MAX_BUFS (i2o_num_controllers * I2O_SCSI_CAN_QUEUE)#define SG_CHAIN_POOL_SZ (SG_MAX_BUFS * SG_CHAIN_BUF_SZ)static int max_sg_len = 0;static chain_buf *sg_chain_pool = NULL;static int sg_chain_tag = 0;static int sg_max_frags = SG_MAX_FRAGS;/* * Retry congested frames. This actually needs pushing down into * i2o core. We should only bother the OSM with this when we can't * queue and retry the frame. Or perhaps we should call the OSM * and its default handler should be this in the core, and this * call a 2nd "I give up" handler in the OSM ? */ static void i2o_retry_run(unsigned long f){ int i; unsigned long flags; save_flags(flags); cli(); for(i=0;i<retry_ct;i++) i2o_post_message(retry_ctrl[i], virt_to_bus(retry[i])); retry_ct=0; restore_flags(flags);}static void flush_pending(void){ int i; unsigned long flags; save_flags(flags); cli(); for(i=0;i<retry_ct;i++) { retry[i][0]&=~0xFFFFFF; retry[i][0]|=I2O_CMD_UTIL_NOP<<24; i2o_post_message(retry_ctrl[i],virt_to_bus(retry[i])); } retry_ct=0; restore_flags(flags);}static void i2o_scsi_reply(struct i2o_handler *h, struct i2o_controller *c, struct i2o_message *msg){ Scsi_Cmnd *current_command; u32 *m = (u32 *)msg; u8 as,ds,st; spin_lock_prefetch(&io_request_lock); if(m[0] & (1<<13)) { printk("IOP fail.\n"); printk("From %d To %d Cmd %d.\n", (m[1]>>12)&0xFFF, m[1]&0xFFF, m[1]>>24); printk("Failure Code %d.\n", m[4]>>24); if(m[4]&(1<<16)) printk("Format error.\n"); if(m[4]&(1<<17)) printk("Path error.\n"); if(m[4]&(1<<18)) printk("Path State.\n"); if(m[4]&(1<<18)) printk("Congestion.\n"); m=(u32 *)bus_to_virt(m[7]); printk("Failing message is %p.\n", m); if((m[4]&(1<<18)) && retry_ct < 32) { retry_ctrl[retry_ct]=c; retry[retry_ct]=m; if(!retry_ct++) { retry_timer.expires=jiffies+1; add_timer(&retry_timer); } } else { /* Create a scsi error for this */ current_command = (Scsi_Cmnd *)m[3]; printk("Aborted %ld\n", current_command->serial_number); spin_lock_irq(&io_request_lock); current_command->result = DID_ERROR << 16; current_command->scsi_done(current_command); spin_unlock_irq(&io_request_lock); /* Now flush the message by making it a NOP */ m[0]&=0x00FFFFFF; m[0]|=(I2O_CMD_UTIL_NOP)<<24; i2o_post_message(c,virt_to_bus(m)); } return; } prefetchw(&queue_depth); /* * Low byte is device status, next is adapter status, * (then one byte reserved), then request status. */ ds=(u8)m[4]; as=(u8)(m[4]>>8); st=(u8)(m[4]>>24); dprintk(("i2o got a scsi reply %08X: ", m[0])); dprintk(("m[2]=%08X: ", m[2])); dprintk(("m[4]=%08X\n", m[4])); if(m[2]&0x80000000) { if(m[2]&0x40000000) { dprintk(("Event.\n")); lun_done=1; return; } printk(KERN_ERR "i2o_scsi: bus reset reply.\n"); return; } current_command = (Scsi_Cmnd *)m[3]; /* * Is this a control request coming back - eg an abort ? */ if(current_command==NULL) { if(st) dprintk(("SCSI abort: %08X", m[4])); dprintk(("SCSI abort completed.\n")); return; } dprintk(("Completed %ld\n", current_command->serial_number)); atomic_dec(&queue_depth); if(st == 0x06) { if(m[5] < current_command->underflow) { int i; printk(KERN_ERR "SCSI: underflow 0x%08X 0x%08X\n", m[5], current_command->underflow); printk("Cmd: "); for(i=0;i<15;i++) printk("%02X ", current_command->cmnd[i]); printk(".\n"); } else st=0; } if(st) { /* An error has occurred */ dprintk((KERN_DEBUG "SCSI error %08X", m[4])); if (as == 0x0E) /* SCSI Reset */ current_command->result = DID_RESET << 16; else if (as == 0x0F) current_command->result = DID_PARITY << 16; else current_command->result = DID_ERROR << 16; } else /* * It worked maybe ? */ current_command->result = DID_OK << 16 | ds; spin_lock(&io_request_lock); current_command->scsi_done(current_command); spin_unlock(&io_request_lock); return;}struct i2o_handler i2o_scsi_handler={ i2o_scsi_reply, NULL, NULL, NULL, "I2O SCSI OSM", 0, I2O_CLASS_SCSI_PERIPHERAL};static int i2o_find_lun(struct i2o_controller *c, struct i2o_device *d, int *target, int *lun){ u8 reply[8]; if(i2o_query_scalar(c, d->lct_data.tid, 0, 3, reply, 4)<0) return -1; *target=reply[0]; if(i2o_query_scalar(c, d->lct_data.tid, 0, 4, reply, 8)<0) return -1; *lun=reply[1]; dprintk(("SCSI (%d,%d)\n", *target, *lun)); return 0;}void i2o_scsi_init(struct i2o_controller *c, struct i2o_device *d, struct Scsi_Host *shpnt){ struct i2o_device *unit; struct i2o_scsi_host *h =(struct i2o_scsi_host *)shpnt->hostdata; int lun; int target; h->controller=c; h->bus_task=d->lct_data.tid; for(target=0;target<16;target++) for(lun=0;lun<8;lun++) h->task[target][lun] = -1; for(unit=c->devices;unit!=NULL;unit=unit->next) { dprintk(("Class %03X, parent %d, want %d.\n", unit->lct_data.class_id, unit->lct_data.parent_tid, d->lct_data.tid)); /* Only look at scsi and fc devices */ if ( (unit->lct_data.class_id != I2O_CLASS_SCSI_PERIPHERAL) && (unit->lct_data.class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL) ) continue; /* On our bus ? */ dprintk(("Found a disk (%d).\n", unit->lct_data.tid)); if ((unit->lct_data.parent_tid == d->lct_data.tid) || (unit->lct_data.parent_tid == d->lct_data.parent_tid) ) { u16 limit; dprintk(("Its ours.\n")); if(i2o_find_lun(c, unit, &target, &lun)==-1) { printk(KERN_ERR "i2o_scsi: Unable to get lun for tid %d.\n", unit->lct_data.tid); continue; } dprintk(("Found disk %d %d.\n", target, lun)); h->task[target][lun]=unit->lct_data.tid; h->tagclock[target][lun]=jiffies; /* Get the max fragments/request */ i2o_query_scalar(c, d->lct_data.tid, 0xF103, 3, &limit, 2); /* sanity */ if ( limit == 0 ) { printk(KERN_WARNING "i2o_scsi: Ignoring unreasonable SG limit of 0 from IOP!\n"); limit = 1; } shpnt->sg_tablesize = limit; dprintk(("i2o_scsi: set scatter-gather to %d.\n", shpnt->sg_tablesize)); } } }int i2o_scsi_detect(Scsi_Host_Template * tpnt){ unsigned long flags; struct Scsi_Host *shpnt = NULL; int i; int count; printk("i2o_scsi.c: %s\n", VERSION_STRING); if(i2o_install_handler(&i2o_scsi_handler)<0) { printk(KERN_ERR "i2o_scsi: Unable to install OSM handler.\n"); return 0; } scsi_context = i2o_scsi_handler.context; if((sg_chain_pool = kmalloc(SG_CHAIN_POOL_SZ, GFP_KERNEL)) == NULL) { printk("i2o_scsi: Unable to alloc %d byte SG chain buffer pool.\n", SG_CHAIN_POOL_SZ); printk("i2o_scsi: SG chaining DISABLED!\n"); sg_max_frags = 11; } else { printk(" chain_pool: %d bytes @ %p\n", SG_CHAIN_POOL_SZ, sg_chain_pool); printk(" (%d byte buffers X %d can_queue X %d i2o controllers)\n", SG_CHAIN_BUF_SZ, I2O_SCSI_CAN_QUEUE, i2o_num_controllers); sg_max_frags = SG_MAX_FRAGS; // 64 } init_timer(&retry_timer); retry_timer.data = 0UL; retry_timer.function = i2o_retry_run; // printk("SCSI OSM at %d.\n", scsi_context); for (count = 0, i = 0; i < MAX_I2O_CONTROLLERS; i++) { struct i2o_controller *c=i2o_find_controller(i); struct i2o_device *d; /* * This controller doesn't exist. */ if(c==NULL) continue; /* * Fixme - we need some altered device locking. This * is racing with device addition in theory. Easy to fix. */ for(d=c->devices;d!=NULL;d=d->next) { /* * bus_adapter, SCSI (obsolete), or FibreChannel busses only */ if( (d->lct_data.class_id!=I2O_CLASS_BUS_ADAPTER_PORT) // bus_adapter// && (d->lct_data.class_id!=I2O_CLASS_FIBRE_CHANNEL_PORT) // FC_PORT ) continue; shpnt = scsi_register(tpnt, sizeof(struct i2o_scsi_host)); if(shpnt==NULL) continue; save_flags(flags); cli(); shpnt->unique_id = (u32)d; shpnt->io_port = 0; shpnt->n_io_port = 0; shpnt->irq = 0; shpnt->this_id = /* Good question */15; restore_flags(flags); i2o_scsi_init(c, d, shpnt); count++; } } i2o_scsi_hosts = count; if(count==0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -