1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657 |
- /*
- * Disk Array driver for HP Smart Array controllers, SCSI Tape module.
- * (C) Copyright 2001, 2007 Hewlett-Packard Development Company, L.P.
- *
- * 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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 300, Boston, MA
- * 02111-1307, USA.
- *
- * Questions/Comments/Bugfixes to iss_storagedev@hp.com
- *
- * Author: Stephen M. Cameron
- */
- #ifdef CONFIG_CISS_SCSI_TAPE
- /* Here we have code to present the driver as a scsi driver
- as it is simultaneously presented as a block driver. The
- reason for doing this is to allow access to SCSI tape drives
- through the array controller. Note in particular, neither
- physical nor logical disks are presented through the scsi layer. */
- #include <linux/timer.h>
- #include <linux/completion.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- #include <asm/atomic.h>
- #include <scsi/scsi_cmnd.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- #include "cciss_scsi.h"
- #define CCISS_ABORT_MSG 0x00
- #define CCISS_RESET_MSG 0x01
- /* some prototypes... */
- static int sendcmd(
- __u8 cmd,
- int ctlr,
- void *buff,
- size_t size,
- unsigned int use_unit_num, /* 0: address the controller,
- 1: address logical volume log_unit,
- 2: address is in scsi3addr */
- unsigned int log_unit,
- __u8 page_code,
- unsigned char *scsi3addr,
- int cmd_type);
- static int cciss_scsi_proc_info(
- struct Scsi_Host *sh,
- char *buffer, /* data buffer */
- char **start, /* where data in buffer starts */
- off_t offset, /* offset from start of imaginary file */
- int length, /* length of data in buffer */
- int func); /* 0 == read, 1 == write */
- static int cciss_scsi_queue_command (struct scsi_cmnd *cmd,
- void (* done)(struct scsi_cmnd *));
- static int cciss_eh_device_reset_handler(struct scsi_cmnd *);
- static int cciss_eh_abort_handler(struct scsi_cmnd *);
- static struct cciss_scsi_hba_t ccissscsi[MAX_CTLR] = {
- { .name = "cciss0", .ndevices = 0 },
- { .name = "cciss1", .ndevices = 0 },
- { .name = "cciss2", .ndevices = 0 },
- { .name = "cciss3", .ndevices = 0 },
- { .name = "cciss4", .ndevices = 0 },
- { .name = "cciss5", .ndevices = 0 },
- { .name = "cciss6", .ndevices = 0 },
- { .name = "cciss7", .ndevices = 0 },
- };
- static struct scsi_host_template cciss_driver_template = {
- .module = THIS_MODULE,
- .name = "cciss",
- .proc_name = "cciss",
- .proc_info = cciss_scsi_proc_info,
- .queuecommand = cciss_scsi_queue_command,
- .can_queue = SCSI_CCISS_CAN_QUEUE,
- .this_id = 7,
- .sg_tablesize = MAXSGENTRIES,
- .cmd_per_lun = 1,
- .use_clustering = DISABLE_CLUSTERING,
- /* Can't have eh_bus_reset_handler or eh_host_reset_handler for cciss */
- .eh_device_reset_handler= cciss_eh_device_reset_handler,
- .eh_abort_handler = cciss_eh_abort_handler,
- };
- #pragma pack(1)
- struct cciss_scsi_cmd_stack_elem_t {
- CommandList_struct cmd;
- ErrorInfo_struct Err;
- __u32 busaddr;
- __u32 pad;
- };
- #pragma pack()
- #define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
- CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
- // plus two for init time usage
- #pragma pack(1)
- struct cciss_scsi_cmd_stack_t {
- struct cciss_scsi_cmd_stack_elem_t *pool;
- struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
- dma_addr_t cmd_pool_handle;
- int top;
- };
- #pragma pack()
- struct cciss_scsi_adapter_data_t {
- struct Scsi_Host *scsi_host;
- struct cciss_scsi_cmd_stack_t cmd_stack;
- int registered;
- spinlock_t lock; // to protect ccissscsi[ctlr];
- };
- #define CPQ_TAPE_LOCK(ctlr, flags) spin_lock_irqsave( \
- &(((struct cciss_scsi_adapter_data_t *) \
- hba[ctlr]->scsi_ctlr)->lock), flags);
- #define CPQ_TAPE_UNLOCK(ctlr, flags) spin_unlock_irqrestore( \
- &(((struct cciss_scsi_adapter_data_t *) \
- hba[ctlr]->scsi_ctlr)->lock), flags);
- static CommandList_struct *
- scsi_cmd_alloc(ctlr_info_t *h)
- {
- /* assume only one process in here at a time, locking done by caller. */
- /* use CCISS_LOCK(ctlr) */
- /* might be better to rewrite how we allocate scsi commands in a way that */
- /* needs no locking at all. */
- /* take the top memory chunk off the stack and return it, if any. */
- struct cciss_scsi_cmd_stack_elem_t *c;
- struct cciss_scsi_adapter_data_t *sa;
- struct cciss_scsi_cmd_stack_t *stk;
- u64bit temp64;
- sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
- stk = &sa->cmd_stack;
- if (stk->top < 0)
- return NULL;
- c = stk->elem[stk->top];
- /* memset(c, 0, sizeof(*c)); */
- memset(&c->cmd, 0, sizeof(c->cmd));
- memset(&c->Err, 0, sizeof(c->Err));
- /* set physical addr of cmd and addr of scsi parameters */
- c->cmd.busaddr = c->busaddr;
- /* (__u32) (stk->cmd_pool_handle +
- (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top)); */
- temp64.val = (__u64) (c->busaddr + sizeof(CommandList_struct));
- /* (__u64) (stk->cmd_pool_handle +
- (sizeof(struct cciss_scsi_cmd_stack_elem_t)*stk->top) +
- sizeof(CommandList_struct)); */
- stk->top--;
- c->cmd.ErrDesc.Addr.lower = temp64.val32.lower;
- c->cmd.ErrDesc.Addr.upper = temp64.val32.upper;
- c->cmd.ErrDesc.Len = sizeof(ErrorInfo_struct);
-
- c->cmd.ctlr = h->ctlr;
- c->cmd.err_info = &c->Err;
- return (CommandList_struct *) c;
- }
- static void
- scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
- {
- /* assume only one process in here at a time, locking done by caller. */
- /* use CCISS_LOCK(ctlr) */
- /* drop the free memory chunk on top of the stack. */
- struct cciss_scsi_adapter_data_t *sa;
- struct cciss_scsi_cmd_stack_t *stk;
- sa = (struct cciss_scsi_adapter_data_t *) h->scsi_ctlr;
- stk = &sa->cmd_stack;
- if (stk->top >= CMD_STACK_SIZE) {
- printk("cciss: scsi_cmd_free called too many times.\n");
- BUG();
- }
- stk->top++;
- stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
- }
- static int
- scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa)
- {
- int i;
- struct cciss_scsi_cmd_stack_t *stk;
- size_t size;
- stk = &sa->cmd_stack;
- size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
- // pci_alloc_consistent guarantees 32-bit DMA address will
- // be used
- stk->pool = (struct cciss_scsi_cmd_stack_elem_t *)
- pci_alloc_consistent(hba[ctlr]->pdev, size, &stk->cmd_pool_handle);
- if (stk->pool == NULL) {
- printk("stk->pool is null\n");
- return -1;
- }
- for (i=0; i<CMD_STACK_SIZE; i++) {
- stk->elem[i] = &stk->pool[i];
- stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle +
- (sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
- }
- stk->top = CMD_STACK_SIZE-1;
- return 0;
- }
- static void
- scsi_cmd_stack_free(int ctlr)
- {
- struct cciss_scsi_adapter_data_t *sa;
- struct cciss_scsi_cmd_stack_t *stk;
- size_t size;
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
- stk = &sa->cmd_stack;
- if (stk->top != CMD_STACK_SIZE-1) {
- printk( "cciss: %d scsi commands are still outstanding.\n",
- CMD_STACK_SIZE - stk->top);
- // BUG();
- printk("WE HAVE A BUG HERE!!! stk=0x%p\n", stk);
- }
- size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
- pci_free_consistent(hba[ctlr]->pdev, size, stk->pool, stk->cmd_pool_handle);
- stk->pool = NULL;
- }
- #if 0
- static int xmargin=8;
- static int amargin=60;
- static void
- print_bytes (unsigned char *c, int len, int hex, int ascii)
- {
- int i;
- unsigned char *x;
- if (hex)
- {
- x = c;
- for (i=0;i<len;i++)
- {
- if ((i % xmargin) == 0 && i>0) printk("\n");
- if ((i % xmargin) == 0) printk("0x%04x:", i);
- printk(" %02x", *x);
- x++;
- }
- printk("\n");
- }
- if (ascii)
- {
- x = c;
- for (i=0;i<len;i++)
- {
- if ((i % amargin) == 0 && i>0) printk("\n");
- if ((i % amargin) == 0) printk("0x%04x:", i);
- if (*x > 26 && *x < 128) printk("%c", *x);
- else printk(".");
- x++;
- }
- printk("\n");
- }
- }
- static void
- print_cmd(CommandList_struct *cp)
- {
- printk("queue:%d\n", cp->Header.ReplyQueue);
- printk("sglist:%d\n", cp->Header.SGList);
- printk("sgtot:%d\n", cp->Header.SGTotal);
- printk("Tag:0x%08x/0x%08x\n", cp->Header.Tag.upper,
- cp->Header.Tag.lower);
- printk("LUN:0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- cp->Header.LUN.LunAddrBytes[0],
- cp->Header.LUN.LunAddrBytes[1],
- cp->Header.LUN.LunAddrBytes[2],
- cp->Header.LUN.LunAddrBytes[3],
- cp->Header.LUN.LunAddrBytes[4],
- cp->Header.LUN.LunAddrBytes[5],
- cp->Header.LUN.LunAddrBytes[6],
- cp->Header.LUN.LunAddrBytes[7]);
- printk("CDBLen:%d\n", cp->Request.CDBLen);
- printk("Type:%d\n",cp->Request.Type.Type);
- printk("Attr:%d\n",cp->Request.Type.Attribute);
- printk(" Dir:%d\n",cp->Request.Type.Direction);
- printk("Timeout:%d\n",cp->Request.Timeout);
- printk( "CDB: %02x %02x %02x %02x %02x %02x %02x %02x"
- " %02x %02x %02x %02x %02x %02x %02x %02x\n",
- cp->Request.CDB[0], cp->Request.CDB[1],
- cp->Request.CDB[2], cp->Request.CDB[3],
- cp->Request.CDB[4], cp->Request.CDB[5],
- cp->Request.CDB[6], cp->Request.CDB[7],
- cp->Request.CDB[8], cp->Request.CDB[9],
- cp->Request.CDB[10], cp->Request.CDB[11],
- cp->Request.CDB[12], cp->Request.CDB[13],
- cp->Request.CDB[14], cp->Request.CDB[15]),
- printk("edesc.Addr: 0x%08x/0%08x, Len = %d\n",
- cp->ErrDesc.Addr.upper, cp->ErrDesc.Addr.lower,
- cp->ErrDesc.Len);
- printk("sgs..........Errorinfo:\n");
- printk("scsistatus:%d\n", cp->err_info->ScsiStatus);
- printk("senselen:%d\n", cp->err_info->SenseLen);
- printk("cmd status:%d\n", cp->err_info->CommandStatus);
- printk("resid cnt:%d\n", cp->err_info->ResidualCnt);
- printk("offense size:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_size);
- printk("offense byte:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_num);
- printk("offense value:%d\n", cp->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-
- }
- #endif
- static int
- find_bus_target_lun(int ctlr, int *bus, int *target, int *lun)
- {
- /* finds an unused bus, target, lun for a new device */
- /* assumes hba[ctlr]->scsi_ctlr->lock is held */
- int i, found=0;
- unsigned char target_taken[CCISS_MAX_SCSI_DEVS_PER_HBA];
- memset(&target_taken[0], 0, CCISS_MAX_SCSI_DEVS_PER_HBA);
- target_taken[SELF_SCSI_ID] = 1;
- for (i=0;i<ccissscsi[ctlr].ndevices;i++)
- target_taken[ccissscsi[ctlr].dev[i].target] = 1;
-
- for (i=0;i<CCISS_MAX_SCSI_DEVS_PER_HBA;i++) {
- if (!target_taken[i]) {
- *bus = 0; *target=i; *lun = 0; found=1;
- break;
- }
- }
- return (!found);
- }
- struct scsi2map {
- char scsi3addr[8];
- int bus, target, lun;
- };
- static int
- cciss_scsi_add_entry(int ctlr, int hostno,
- struct cciss_scsi_dev_t *device,
- struct scsi2map *added, int *nadded)
- {
- /* assumes hba[ctlr]->scsi_ctlr->lock is held */
- int n = ccissscsi[ctlr].ndevices;
- struct cciss_scsi_dev_t *sd;
- int i, bus, target, lun;
- unsigned char addr1[8], addr2[8];
- if (n >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
- printk("cciss%d: Too many devices, "
- "some will be inaccessible.\n", ctlr);
- return -1;
- }
- bus = target = -1;
- lun = 0;
- /* Is this device a non-zero lun of a multi-lun device */
- /* byte 4 of the 8-byte LUN addr will contain the logical unit no. */
- if (device->scsi3addr[4] != 0) {
- /* Search through our list and find the device which */
- /* has the same 8 byte LUN address, excepting byte 4. */
- /* Assign the same bus and target for this new LUN. */
- /* Use the logical unit number from the firmware. */
- memcpy(addr1, device->scsi3addr, 8);
- addr1[4] = 0;
- for (i = 0; i < n; i++) {
- sd = &ccissscsi[ctlr].dev[i];
- memcpy(addr2, sd->scsi3addr, 8);
- addr2[4] = 0;
- /* differ only in byte 4? */
- if (memcmp(addr1, addr2, 8) == 0) {
- bus = sd->bus;
- target = sd->target;
- lun = device->scsi3addr[4];
- break;
- }
- }
- }
- sd = &ccissscsi[ctlr].dev[n];
- if (lun == 0) {
- if (find_bus_target_lun(ctlr,
- &sd->bus, &sd->target, &sd->lun) != 0)
- return -1;
- } else {
- sd->bus = bus;
- sd->target = target;
- sd->lun = lun;
- }
- added[*nadded].bus = sd->bus;
- added[*nadded].target = sd->target;
- added[*nadded].lun = sd->lun;
- (*nadded)++;
- memcpy(sd->scsi3addr, device->scsi3addr, 8);
- memcpy(sd->vendor, device->vendor, sizeof(sd->vendor));
- memcpy(sd->revision, device->revision, sizeof(sd->revision));
- memcpy(sd->device_id, device->device_id, sizeof(sd->device_id));
- sd->devtype = device->devtype;
- ccissscsi[ctlr].ndevices++;
- /* initially, (before registering with scsi layer) we don't
- know our hostno and we don't want to print anything first
- time anyway (the scsi layer's inquiries will show that info) */
- if (hostno != -1)
- printk("cciss%d: %s device c%db%dt%dl%d added.\n",
- ctlr, scsi_device_type(sd->devtype), hostno,
- sd->bus, sd->target, sd->lun);
- return 0;
- }
- static void
- cciss_scsi_remove_entry(int ctlr, int hostno, int entry,
- struct scsi2map *removed, int *nremoved)
- {
- /* assumes hba[ctlr]->scsi_ctlr->lock is held */
- int i;
- struct cciss_scsi_dev_t sd;
- if (entry < 0 || entry >= CCISS_MAX_SCSI_DEVS_PER_HBA) return;
- sd = ccissscsi[ctlr].dev[entry];
- removed[*nremoved].bus = sd.bus;
- removed[*nremoved].target = sd.target;
- removed[*nremoved].lun = sd.lun;
- (*nremoved)++;
- for (i=entry;i<ccissscsi[ctlr].ndevices-1;i++)
- ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
- ccissscsi[ctlr].ndevices--;
- printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, scsi_device_type(sd.devtype), hostno,
- sd.bus, sd.target, sd.lun);
- }
- #define SCSI3ADDR_EQ(a,b) ( \
- (a)[7] == (b)[7] && \
- (a)[6] == (b)[6] && \
- (a)[5] == (b)[5] && \
- (a)[4] == (b)[4] && \
- (a)[3] == (b)[3] && \
- (a)[2] == (b)[2] && \
- (a)[1] == (b)[1] && \
- (a)[0] == (b)[0])
- static void fixup_botched_add(int ctlr, char *scsi3addr)
- {
- /* called when scsi_add_device fails in order to re-adjust */
- /* ccissscsi[] to match the mid layer's view. */
- unsigned long flags;
- int i, j;
- CPQ_TAPE_LOCK(ctlr, flags);
- for (i = 0; i < ccissscsi[ctlr].ndevices; i++) {
- if (memcmp(scsi3addr,
- ccissscsi[ctlr].dev[i].scsi3addr, 8) == 0) {
- for (j = i; j < ccissscsi[ctlr].ndevices-1; j++)
- ccissscsi[ctlr].dev[j] =
- ccissscsi[ctlr].dev[j+1];
- ccissscsi[ctlr].ndevices--;
- break;
- }
- }
- CPQ_TAPE_UNLOCK(ctlr, flags);
- }
- static int device_is_the_same(struct cciss_scsi_dev_t *dev1,
- struct cciss_scsi_dev_t *dev2)
- {
- return dev1->devtype == dev2->devtype &&
- memcmp(dev1->scsi3addr, dev2->scsi3addr,
- sizeof(dev1->scsi3addr)) == 0 &&
- memcmp(dev1->device_id, dev2->device_id,
- sizeof(dev1->device_id)) == 0 &&
- memcmp(dev1->vendor, dev2->vendor,
- sizeof(dev1->vendor)) == 0 &&
- memcmp(dev1->model, dev2->model,
- sizeof(dev1->model)) == 0 &&
- memcmp(dev1->revision, dev2->revision,
- sizeof(dev1->revision)) == 0;
- }
- static int
- adjust_cciss_scsi_table(int ctlr, int hostno,
- struct cciss_scsi_dev_t sd[], int nsds)
- {
- /* sd contains scsi3 addresses and devtypes, but
- bus target and lun are not filled in. This funciton
- takes what's in sd to be the current and adjusts
- ccissscsi[] to be in line with what's in sd. */
- int i,j, found, changes=0;
- struct cciss_scsi_dev_t *csd;
- unsigned long flags;
- struct scsi2map *added, *removed;
- int nadded, nremoved;
- struct Scsi_Host *sh = NULL;
- added = kzalloc(sizeof(*added) * CCISS_MAX_SCSI_DEVS_PER_HBA,
- GFP_KERNEL);
- removed = kzalloc(sizeof(*removed) * CCISS_MAX_SCSI_DEVS_PER_HBA,
- GFP_KERNEL);
- if (!added || !removed) {
- printk(KERN_WARNING "cciss%d: Out of memory in "
- "adjust_cciss_scsi_table\n", ctlr);
- goto free_and_out;
- }
- CPQ_TAPE_LOCK(ctlr, flags);
- if (hostno != -1) /* if it's not the first time... */
- sh = ((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->scsi_host;
- /* find any devices in ccissscsi[] that are not in
- sd[] and remove them from ccissscsi[] */
- i = 0;
- nremoved = 0;
- nadded = 0;
- while(i<ccissscsi[ctlr].ndevices) {
- csd = &ccissscsi[ctlr].dev[i];
- found=0;
- for (j=0;j<nsds;j++) {
- if (SCSI3ADDR_EQ(sd[j].scsi3addr,
- csd->scsi3addr)) {
- if (device_is_the_same(&sd[j], csd))
- found=2;
- else
- found=1;
- break;
- }
- }
- if (found == 0) { /* device no longer present. */
- changes++;
- /* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, scsi_device_type(csd->devtype), hostno,
- csd->bus, csd->target, csd->lun); */
- cciss_scsi_remove_entry(ctlr, hostno, i,
- removed, &nremoved);
- /* remove ^^^, hence i not incremented */
- } else if (found == 1) { /* device is different in some way */
- changes++;
- printk("cciss%d: device c%db%dt%dl%d has changed.\n",
- ctlr, hostno, csd->bus, csd->target, csd->lun);
- cciss_scsi_remove_entry(ctlr, hostno, i,
- removed, &nremoved);
- /* remove ^^^, hence i not incremented */
- if (cciss_scsi_add_entry(ctlr, hostno, &sd[j],
- added, &nadded) != 0)
- /* we just removed one, so add can't fail. */
- BUG();
- csd->devtype = sd[j].devtype;
- memcpy(csd->device_id, sd[j].device_id,
- sizeof(csd->device_id));
- memcpy(csd->vendor, sd[j].vendor,
- sizeof(csd->vendor));
- memcpy(csd->model, sd[j].model,
- sizeof(csd->model));
- memcpy(csd->revision, sd[j].revision,
- sizeof(csd->revision));
- } else /* device is same as it ever was, */
- i++; /* so just move along. */
- }
- /* Now, make sure every device listed in sd[] is also
- listed in ccissscsi[], adding them if they aren't found */
- for (i=0;i<nsds;i++) {
- found=0;
- for (j=0;j<ccissscsi[ctlr].ndevices;j++) {
- csd = &ccissscsi[ctlr].dev[j];
- if (SCSI3ADDR_EQ(sd[i].scsi3addr,
- csd->scsi3addr)) {
- if (device_is_the_same(&sd[i], csd))
- found=2; /* found device */
- else
- found=1; /* found a bug. */
- break;
- }
- }
- if (!found) {
- changes++;
- if (cciss_scsi_add_entry(ctlr, hostno, &sd[i],
- added, &nadded) != 0)
- break;
- } else if (found == 1) {
- /* should never happen... */
- changes++;
- printk(KERN_WARNING "cciss%d: device "
- "unexpectedly changed\n", ctlr);
- /* but if it does happen, we just ignore that device */
- }
- }
- CPQ_TAPE_UNLOCK(ctlr, flags);
- /* Don't notify scsi mid layer of any changes the first time through */
- /* (or if there are no changes) scsi_scan_host will do it later the */
- /* first time through. */
- if (hostno == -1 || !changes)
- goto free_and_out;
- /* Notify scsi mid layer of any removed devices */
- for (i = 0; i < nremoved; i++) {
- struct scsi_device *sdev =
- scsi_device_lookup(sh, removed[i].bus,
- removed[i].target, removed[i].lun);
- if (sdev != NULL) {
- scsi_remove_device(sdev);
- scsi_device_put(sdev);
- } else {
- /* We don't expect to get here. */
- /* future cmds to this device will get selection */
- /* timeout as if the device was gone. */
- printk(KERN_WARNING "cciss%d: didn't find "
- "c%db%dt%dl%d\n for removal.",
- ctlr, hostno, removed[i].bus,
- removed[i].target, removed[i].lun);
- }
- }
- /* Notify scsi mid layer of any added devices */
- for (i = 0; i < nadded; i++) {
- int rc;
- rc = scsi_add_device(sh, added[i].bus,
- added[i].target, added[i].lun);
- if (rc == 0)
- continue;
- printk(KERN_WARNING "cciss%d: scsi_add_device "
- "c%db%dt%dl%d failed, device not added.\n",
- ctlr, hostno,
- added[i].bus, added[i].target, added[i].lun);
- /* now we have to remove it from ccissscsi, */
- /* since it didn't get added to scsi mid layer */
- fixup_botched_add(ctlr, added[i].scsi3addr);
- }
- free_and_out:
- kfree(added);
- kfree(removed);
- return 0;
- }
- static int
- lookup_scsi3addr(int ctlr, int bus, int target, int lun, char *scsi3addr)
- {
- int i;
- struct cciss_scsi_dev_t *sd;
- unsigned long flags;
- CPQ_TAPE_LOCK(ctlr, flags);
- for (i=0;i<ccissscsi[ctlr].ndevices;i++) {
- sd = &ccissscsi[ctlr].dev[i];
- if (sd->bus == bus &&
- sd->target == target &&
- sd->lun == lun) {
- memcpy(scsi3addr, &sd->scsi3addr[0], 8);
- CPQ_TAPE_UNLOCK(ctlr, flags);
- return 0;
- }
- }
- CPQ_TAPE_UNLOCK(ctlr, flags);
- return -1;
- }
- static void
- cciss_scsi_setup(int cntl_num)
- {
- struct cciss_scsi_adapter_data_t * shba;
- ccissscsi[cntl_num].ndevices = 0;
- shba = (struct cciss_scsi_adapter_data_t *)
- kmalloc(sizeof(*shba), GFP_KERNEL);
- if (shba == NULL)
- return;
- shba->scsi_host = NULL;
- spin_lock_init(&shba->lock);
- shba->registered = 0;
- if (scsi_cmd_stack_setup(cntl_num, shba) != 0) {
- kfree(shba);
- shba = NULL;
- }
- hba[cntl_num]->scsi_ctlr = (void *) shba;
- return;
- }
- static void
- complete_scsi_command( CommandList_struct *cp, int timeout, __u32 tag)
- {
- struct scsi_cmnd *cmd;
- ctlr_info_t *ctlr;
- ErrorInfo_struct *ei;
- ei = cp->err_info;
- /* First, see if it was a message rather than a command */
- if (cp->Request.Type.Type == TYPE_MSG) {
- cp->cmd_type = CMD_MSG_DONE;
- return;
- }
- cmd = (struct scsi_cmnd *) cp->scsi_cmd;
- ctlr = hba[cp->ctlr];
- scsi_dma_unmap(cmd);
- cmd->result = (DID_OK << 16); /* host byte */
- cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
- /* cmd->result |= (GOOD < 1); */ /* status byte */
- cmd->result |= (ei->ScsiStatus);
- /* printk("Scsistatus is 0x%02x\n", ei->ScsiStatus); */
- /* copy the sense data whether we need to or not. */
- memcpy(cmd->sense_buffer, ei->SenseInfo,
- ei->SenseLen > SCSI_SENSE_BUFFERSIZE ?
- SCSI_SENSE_BUFFERSIZE :
- ei->SenseLen);
- scsi_set_resid(cmd, ei->ResidualCnt);
- if(ei->CommandStatus != 0)
- { /* an error has occurred */
- switch(ei->CommandStatus)
- {
- case CMD_TARGET_STATUS:
- /* Pass it up to the upper layers... */
- if( ei->ScsiStatus)
- {
- #if 0
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status = %x\n",
- cp,
- ei->ScsiStatus);
- #endif
- cmd->result |= (ei->ScsiStatus < 1);
- }
- else { /* scsi status is zero??? How??? */
-
- /* Ordinarily, this case should never happen, but there is a bug
- in some released firmware revisions that allows it to happen
- if, for example, a 4100 backplane loses power and the tape
- drive is in it. We assume that it's a fatal error of some
- kind because we can't show that it wasn't. We will make it
- look like selection timeout since that is the most common
- reason for this to occur, and it's severe enough. */
- cmd->result = DID_NO_CONNECT << 16;
- }
- break;
- case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
- break;
- case CMD_DATA_OVERRUN:
- printk(KERN_WARNING "cciss: cp %p has"
- " completed with data overrun "
- "reported\n", cp);
- break;
- case CMD_INVALID: {
- /* print_bytes(cp, sizeof(*cp), 1, 0);
- print_cmd(cp); */
- /* We get CMD_INVALID if you address a non-existent tape drive instead
- of a selection timeout (no response). You will see this if you yank
- out a tape drive, then try to access it. This is kind of a shame
- because it means that any other CMD_INVALID (e.g. driver bug) will
- get interpreted as a missing target. */
- cmd->result = DID_NO_CONNECT << 16;
- }
- break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cp %p has "
- "protocol error \n", cp);
- break;
- case CMD_HARDWARE_ERR:
- cmd->result = DID_ERROR << 16;
- printk(KERN_WARNING "cciss: cp %p had "
- " hardware error\n", cp);
- break;
- case CMD_CONNECTION_LOST:
- cmd->result = DID_ERROR << 16;
- printk(KERN_WARNING "cciss: cp %p had "
- "connection lost\n", cp);
- break;
- case CMD_ABORTED:
- cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "cciss: cp %p was "
- "aborted\n", cp);
- break;
- case CMD_ABORT_FAILED:
- cmd->result = DID_ERROR << 16;
- printk(KERN_WARNING "cciss: cp %p reports "
- "abort failed\n", cp);
- break;
- case CMD_UNSOLICITED_ABORT:
- cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "cciss: cp %p aborted "
- "do to an unsolicited abort\n", cp);
- break;
- case CMD_TIMEOUT:
- cmd->result = DID_TIME_OUT << 16;
- printk(KERN_WARNING "cciss: cp %p timedout\n",
- cp);
- break;
- default:
- cmd->result = DID_ERROR << 16;
- printk(KERN_WARNING "cciss: cp %p returned "
- "unknown status %x\n", cp,
- ei->CommandStatus);
- }
- }
- // printk("c:%p:c%db%dt%dl%d ", cmd, ctlr->ctlr, cmd->channel,
- // cmd->target, cmd->lun);
- cmd->scsi_done(cmd);
- scsi_cmd_free(ctlr, cp);
- }
- static int
- cciss_scsi_detect(int ctlr)
- {
- struct Scsi_Host *sh;
- int error;
- sh = scsi_host_alloc(&cciss_driver_template, sizeof(struct ctlr_info *));
- if (sh == NULL)
- goto fail;
- sh->io_port = 0; // good enough? FIXME,
- sh->n_io_port = 0; // I don't think we use these two...
- sh->this_id = SELF_SCSI_ID;
- ((struct cciss_scsi_adapter_data_t *)
- hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
- sh->hostdata[0] = (unsigned long) hba[ctlr];
- sh->irq = hba[ctlr]->intr[SIMPLE_MODE_INT];
- sh->unique_id = sh->irq;
- error = scsi_add_host(sh, &hba[ctlr]->pdev->dev);
- if (error)
- goto fail_host_put;
- scsi_scan_host(sh);
- return 1;
- fail_host_put:
- scsi_host_put(sh);
- fail:
- return 0;
- }
- static void
- cciss_unmap_one(struct pci_dev *pdev,
- CommandList_struct *cp,
- size_t buflen,
- int data_direction)
- {
- u64bit addr64;
- addr64.val32.lower = cp->SG[0].Addr.lower;
- addr64.val32.upper = cp->SG[0].Addr.upper;
- pci_unmap_single(pdev, (dma_addr_t) addr64.val, buflen, data_direction);
- }
- static void
- cciss_map_one(struct pci_dev *pdev,
- CommandList_struct *cp,
- unsigned char *buf,
- size_t buflen,
- int data_direction)
- {
- __u64 addr64;
- addr64 = (__u64) pci_map_single(pdev, buf, buflen, data_direction);
- cp->SG[0].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[0].Len = buflen;
- cp->Header.SGList = (__u8) 1; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) 1; /* total sgs in this cmd list */
- }
- static int
- cciss_scsi_do_simple_cmd(ctlr_info_t *c,
- CommandList_struct *cp,
- unsigned char *scsi3addr,
- unsigned char *cdb,
- unsigned char cdblen,
- unsigned char *buf, int bufsize,
- int direction)
- {
- unsigned long flags;
- DECLARE_COMPLETION_ONSTACK(wait);
- cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
- cp->scsi_cmd = NULL;
- cp->Header.ReplyQueue = 0; // unused in simple mode
- memcpy(&cp->Header.LUN, scsi3addr, sizeof(cp->Header.LUN));
- cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
- // Fill in the request block...
- /* printk("Using scsi3addr 0x%02x%0x2%0x2%0x2%0x2%0x2%0x2%0x2\n",
- scsi3addr[0], scsi3addr[1], scsi3addr[2], scsi3addr[3],
- scsi3addr[4], scsi3addr[5], scsi3addr[6], scsi3addr[7]); */
- memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
- memcpy(cp->Request.CDB, cdb, cdblen);
- cp->Request.Timeout = 0;
- cp->Request.CDBLen = cdblen;
- cp->Request.Type.Type = TYPE_CMD;
- cp->Request.Type.Attribute = ATTR_SIMPLE;
- cp->Request.Type.Direction = direction;
- /* Fill in the SG list and do dma mapping */
- cciss_map_one(c->pdev, cp, (unsigned char *) buf,
- bufsize, DMA_FROM_DEVICE);
- cp->waiting = &wait;
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
- addQ(&c->reqQ, cp);
- c->Qdepth++;
- start_io(c);
- spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
- wait_for_completion(&wait);
- /* undo the dma mapping */
- cciss_unmap_one(c->pdev, cp, bufsize, DMA_FROM_DEVICE);
- return(0);
- }
- static void
- cciss_scsi_interpret_error(CommandList_struct *cp)
- {
- ErrorInfo_struct *ei;
- ei = cp->err_info;
- switch(ei->CommandStatus)
- {
- case CMD_TARGET_STATUS:
- printk(KERN_WARNING "cciss: cmd %p has "
- "completed with errors\n", cp);
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status = %x\n",
- cp,
- ei->ScsiStatus);
- if (ei->ScsiStatus == 0)
- printk(KERN_WARNING
- "cciss:SCSI status is abnormally zero. "
- "(probably indicates selection timeout "
- "reported incorrectly due to a known "
- "firmware bug, circa July, 2001.)\n");
- break;
- case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
- printk("UNDERRUN\n");
- break;
- case CMD_DATA_OVERRUN:
- printk(KERN_WARNING "cciss: cp %p has"
- " completed with data overrun "
- "reported\n", cp);
- break;
- case CMD_INVALID: {
- /* controller unfortunately reports SCSI passthru's */
- /* to non-existent targets as invalid commands. */
- printk(KERN_WARNING "cciss: cp %p is "
- "reported invalid (probably means "
- "target device no longer present)\n",
- cp);
- /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0);
- print_cmd(cp); */
- }
- break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cp %p has "
- "protocol error \n", cp);
- break;
- case CMD_HARDWARE_ERR:
- /* cmd->result = DID_ERROR << 16; */
- printk(KERN_WARNING "cciss: cp %p had "
- " hardware error\n", cp);
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cp %p had "
- "connection lost\n", cp);
- break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cp %p was "
- "aborted\n", cp);
- break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cp %p reports "
- "abort failed\n", cp);
- break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING "cciss: cp %p aborted "
- "do to an unsolicited abort\n", cp);
- break;
- case CMD_TIMEOUT:
- printk(KERN_WARNING "cciss: cp %p timedout\n",
- cp);
- break;
- default:
- printk(KERN_WARNING "cciss: cp %p returned "
- "unknown status %x\n", cp,
- ei->CommandStatus);
- }
- }
- static int
- cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr,
- unsigned char page, unsigned char *buf,
- unsigned char bufsize)
- {
- int rc;
- CommandList_struct *cp;
- char cdb[6];
- ErrorInfo_struct *ei;
- unsigned long flags;
- spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
- cp = scsi_cmd_alloc(c);
- spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
- if (cp == NULL) { /* trouble... */
- printk("cmd_alloc returned NULL!\n");
- return -1;
- }
- ei = cp->err_info;
- cdb[0] = CISS_INQUIRY;
- cdb[1] = (page != 0);
- cdb[2] = page;
- cdb[3] = 0;
- cdb[4] = bufsize;
- cdb[5] = 0;
- rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb,
- 6, buf, bufsize, XFER_READ);
- if (rc != 0) return rc; /* something went wrong */
- if (ei->CommandStatus != 0 &&
- ei->CommandStatus != CMD_DATA_UNDERRUN) {
- cciss_scsi_interpret_error(cp);
- rc = -1;
- }
- spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
- scsi_cmd_free(c, cp);
- spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
- return rc;
- }
- /* Get the device id from inquiry page 0x83 */
- static int cciss_scsi_get_device_id(ctlr_info_t *c, unsigned char *scsi3addr,
- unsigned char *device_id, int buflen)
- {
- int rc;
- unsigned char *buf;
- if (buflen > 16)
- buflen = 16;
- buf = kzalloc(64, GFP_KERNEL);
- if (!buf)
- return -1;
- rc = cciss_scsi_do_inquiry(c, scsi3addr, 0x83, buf, 64);
- if (rc == 0)
- memcpy(device_id, &buf[8], buflen);
- kfree(buf);
- return rc != 0;
- }
- static int
- cciss_scsi_do_report_phys_luns(ctlr_info_t *c,
- ReportLunData_struct *buf, int bufsize)
- {
- int rc;
- CommandList_struct *cp;
- unsigned char cdb[12];
- unsigned char scsi3addr[8];
- ErrorInfo_struct *ei;
- unsigned long flags;
- spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
- cp = scsi_cmd_alloc(c);
- spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
- if (cp == NULL) { /* trouble... */
- printk("cmd_alloc returned NULL!\n");
- return -1;
- }
- memset(&scsi3addr[0], 0, 8); /* address the controller */
- cdb[0] = CISS_REPORT_PHYS;
- cdb[1] = 0;
- cdb[2] = 0;
- cdb[3] = 0;
- cdb[4] = 0;
- cdb[5] = 0;
- cdb[6] = (bufsize >> 24) & 0xFF; //MSB
- cdb[7] = (bufsize >> 16) & 0xFF;
- cdb[8] = (bufsize >> 8) & 0xFF;
- cdb[9] = bufsize & 0xFF;
- cdb[10] = 0;
- cdb[11] = 0;
- rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr,
- cdb, 12,
- (unsigned char *) buf,
- bufsize, XFER_READ);
- if (rc != 0) return rc; /* something went wrong */
- ei = cp->err_info;
- if (ei->CommandStatus != 0 &&
- ei->CommandStatus != CMD_DATA_UNDERRUN) {
- cciss_scsi_interpret_error(cp);
- rc = -1;
- }
- spin_lock_irqsave(CCISS_LOCK(c->ctlr), flags);
- scsi_cmd_free(c, cp);
- spin_unlock_irqrestore(CCISS_LOCK(c->ctlr), flags);
- return rc;
- }
- static void
- cciss_update_non_disk_devices(int cntl_num, int hostno)
- {
- /* the idea here is we could get notified from /proc
- that some devices have changed, so we do a report
- physical luns cmd, and adjust our list of devices
- accordingly. (We can't rely on the scsi-mid layer just
- doing inquiries, because the "busses" that the scsi
- mid-layer probes are totally fabricated by this driver,
- so new devices wouldn't show up.
- the scsi3addr's of devices won't change so long as the
- adapter is not reset. That means we can rescan and
- tell which devices we already know about, vs. new
- devices, vs. disappearing devices.
- Also, if you yank out a tape drive, then put in a disk
- in it's place, (say, a configured volume from another
- array controller for instance) _don't_ poke this driver
- (so it thinks it's still a tape, but _do_ poke the scsi
- mid layer, so it does an inquiry... the scsi mid layer
- will see the physical disk. This would be bad. Need to
- think about how to prevent that. One idea would be to
- snoop all scsi responses and if an inquiry repsonse comes
- back that reports a disk, chuck it an return selection
- timeout instead and adjust our table... Not sure i like
- that though.
- */
- #define OBDR_TAPE_INQ_SIZE 49
- #define OBDR_TAPE_SIG "$DR-10"
- ReportLunData_struct *ld_buff;
- unsigned char *inq_buff;
- unsigned char scsi3addr[8];
- ctlr_info_t *c;
- __u32 num_luns=0;
- unsigned char *ch;
- struct cciss_scsi_dev_t *currentsd, *this_device;
- int ncurrent=0;
- int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8;
- int i;
- c = (ctlr_info_t *) hba[cntl_num];
- ld_buff = kzalloc(reportlunsize, GFP_KERNEL);
- inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
- currentsd = kzalloc(sizeof(*currentsd) *
- (CCISS_MAX_SCSI_DEVS_PER_HBA+1), GFP_KERNEL);
- if (ld_buff == NULL || inq_buff == NULL || currentsd == NULL) {
- printk(KERN_ERR "cciss: out of memory\n");
- goto out;
- }
- this_device = ¤tsd[CCISS_MAX_SCSI_DEVS_PER_HBA];
- if (cciss_scsi_do_report_phys_luns(c, ld_buff, reportlunsize) == 0) {
- ch = &ld_buff->LUNListLength[0];
- num_luns = ((ch[0]<<24) | (ch[1]<<16) | (ch[2]<<8) | ch[3]) / 8;
- if (num_luns > CISS_MAX_PHYS_LUN) {
- printk(KERN_WARNING
- "cciss: Maximum physical LUNs (%d) exceeded. "
- "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN,
- num_luns - CISS_MAX_PHYS_LUN);
- num_luns = CISS_MAX_PHYS_LUN;
- }
- }
- else {
- printk(KERN_ERR "cciss: Report physical LUNs failed.\n");
- goto out;
- }
- /* adjust our table of devices */
- for (i = 0; i < num_luns; i++) {
- /* for each physical lun, do an inquiry */
- if (ld_buff->LUN[i][3] & 0xC0) continue;
- memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE);
- memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8);
- if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, 0, inq_buff,
- (unsigned char) OBDR_TAPE_INQ_SIZE) != 0)
- /* Inquiry failed (msg printed already) */
- continue; /* so we will skip this device. */
- this_device->devtype = (inq_buff[0] & 0x1f);
- this_device->bus = -1;
- this_device->target = -1;
- this_device->lun = -1;
- memcpy(this_device->scsi3addr, scsi3addr, 8);
- memcpy(this_device->vendor, &inq_buff[8],
- sizeof(this_device->vendor));
- memcpy(this_device->model, &inq_buff[16],
- sizeof(this_device->model));
- memcpy(this_device->revision, &inq_buff[32],
- sizeof(this_device->revision));
- memset(this_device->device_id, 0,
- sizeof(this_device->device_id));
- cciss_scsi_get_device_id(hba[cntl_num], scsi3addr,
- this_device->device_id, sizeof(this_device->device_id));
- switch (this_device->devtype)
- {
- case 0x05: /* CD-ROM */ {
- /* We don't *really* support actual CD-ROM devices,
- * just this "One Button Disaster Recovery" tape drive
- * which temporarily pretends to be a CD-ROM drive.
- * So we check that the device is really an OBDR tape
- * device by checking for "$DR-10" in bytes 43-48 of
- * the inquiry data.
- */
- char obdr_sig[7];
- strncpy(obdr_sig, &inq_buff[43], 6);
- obdr_sig[6] = '\0';
- if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0)
- /* Not OBDR device, ignore it. */
- break;
- }
- /* fall through . . . */
- case 0x01: /* sequential access, (tape) */
- case 0x08: /* medium changer */
- if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
- printk(KERN_INFO "cciss%d: %s ignored, "
- "too many devices.\n", cntl_num,
- scsi_device_type(this_device->devtype));
- break;
- }
- currentsd[ncurrent] = *this_device;
- ncurrent++;
- break;
- default:
- break;
- }
- }
- adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);
- out:
- kfree(inq_buff);
- kfree(ld_buff);
- kfree(currentsd);
- return;
- }
- static int
- is_keyword(char *ptr, int len, char *verb) // Thanks to ncr53c8xx.c
- {
- int verb_len = strlen(verb);
- if (len >= verb_len && !memcmp(verb,ptr,verb_len))
- return verb_len;
- else
- return 0;
- }
- static int
- cciss_scsi_user_command(int ctlr, int hostno, char *buffer, int length)
- {
- int arg_len;
- if ((arg_len = is_keyword(buffer, length, "rescan")) != 0)
- cciss_update_non_disk_devices(ctlr, hostno);
- else
- return -EINVAL;
- return length;
- }
- static int
- cciss_scsi_proc_info(struct Scsi_Host *sh,
- char *buffer, /* data buffer */
- char **start, /* where data in buffer starts */
- off_t offset, /* offset from start of imaginary file */
- int length, /* length of data in buffer */
- int func) /* 0 == read, 1 == write */
- {
- int buflen, datalen;
- ctlr_info_t *ci;
- int i;
- int cntl_num;
- ci = (ctlr_info_t *) sh->hostdata[0];
- if (ci == NULL) /* This really shouldn't ever happen. */
- return -EINVAL;
- cntl_num = ci->ctlr; /* Get our index into the hba[] array */
- if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */
- buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n",
- cntl_num, sh->host_no);
- /* this information is needed by apps to know which cciss
- device corresponds to which scsi host number without
- having to open a scsi target device node. The device
- information is not a duplicate of /proc/scsi/scsi because
- the two may be out of sync due to scsi hotplug, rather
- this info is for an app to be able to use to know how to
- get them back in sync. */
- for (i=0;i<ccissscsi[cntl_num].ndevices;i++) {
- struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i];
- buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d "
- "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- sh->host_no, sd->bus, sd->target, sd->lun,
- sd->devtype,
- sd->scsi3addr[0], sd->scsi3addr[1],
- sd->scsi3addr[2], sd->scsi3addr[3],
- sd->scsi3addr[4], sd->scsi3addr[5],
- sd->scsi3addr[6], sd->scsi3addr[7]);
- }
- datalen = buflen - offset;
- if (datalen < 0) { /* they're reading past EOF. */
- datalen = 0;
- *start = buffer+buflen;
- } else
- *start = buffer + offset;
- return(datalen);
- } else /* User is writing to /proc/scsi/cciss*?/?* ... */
- return cciss_scsi_user_command(cntl_num, sh->host_no,
- buffer, length);
- }
- /* cciss_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
- dma mapping and fills in the scatter gather entries of the
- cciss command, cp. */
- static void
- cciss_scatter_gather(struct pci_dev *pdev,
- CommandList_struct *cp,
- struct scsi_cmnd *cmd)
- {
- unsigned int len;
- struct scatterlist *sg;
- __u64 addr64;
- int use_sg, i;
- BUG_ON(scsi_sg_count(cmd) > MAXSGENTRIES);
- use_sg = scsi_dma_map(cmd);
- if (use_sg) { /* not too many addrs? */
- scsi_for_each_sg(cmd, sg, use_sg, i) {
- addr64 = (__u64) sg_dma_address(sg);
- len = sg_dma_len(sg);
- cp->SG[i].Addr.lower =
- (__u32) (addr64 & (__u64) 0x00000000FFFFFFFF);
- cp->SG[i].Addr.upper =
- (__u32) ((addr64 >> 32) & (__u64) 0x00000000FFFFFFFF);
- cp->SG[i].Len = len;
- cp->SG[i].Ext = 0; // we are not chaining
- }
- }
- cp->Header.SGList = (__u8) use_sg; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (__u16) use_sg; /* total sgs in this cmd list */
- return;
- }
- static int
- cciss_scsi_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
- {
- ctlr_info_t **c;
- int ctlr, rc;
- unsigned char scsi3addr[8];
- CommandList_struct *cp;
- unsigned long flags;
- // Get the ptr to our adapter structure (hba[i]) out of cmd->host.
- // We violate cmd->host privacy here. (Is there another way?)
- c = (ctlr_info_t **) &cmd->device->host->hostdata[0];
- ctlr = (*c)->ctlr;
- rc = lookup_scsi3addr(ctlr, cmd->device->channel, cmd->device->id,
- cmd->device->lun, scsi3addr);
- if (rc != 0) {
- /* the scsi nexus does not match any that we presented... */
- /* pretend to mid layer that we got selection timeout */
- cmd->result = DID_NO_CONNECT << 16;
- done(cmd);
- /* we might want to think about registering controller itself
- as a processor device on the bus so sg binds to it. */
- return 0;
- }
- /* printk("cciss_queue_command, p=%p, cmd=0x%02x, c%db%dt%dl%d\n",
- cmd, cmd->cmnd[0], ctlr, cmd->channel, cmd->target, cmd->lun);*/
- // printk("q:%p:c%db%dt%dl%d ", cmd, ctlr, cmd->channel,
- // cmd->target, cmd->lun);
- /* Ok, we have a reasonable scsi nexus, so send the cmd down, and
- see what the device thinks of it. */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- cp = scsi_cmd_alloc(*c);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- if (cp == NULL) { /* trouble... */
- printk("scsi_cmd_alloc returned NULL!\n");
- /* FIXME: next 3 lines are -> BAD! <- */
- cmd->result = DID_NO_CONNECT << 16;
- done(cmd);
- return 0;
- }
- // Fill in the command list header
- cmd->scsi_done = done; // save this for use by completion code
- // save cp in case we have to abort it
- cmd->host_scribble = (unsigned char *) cp;
- cp->cmd_type = CMD_SCSI;
- cp->scsi_cmd = cmd;
- cp->Header.ReplyQueue = 0; // unused in simple mode
- memcpy(&cp->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
- cp->Header.Tag.lower = cp->busaddr; // Use k. address of cmd as tag
-
- // Fill in the request block...
- cp->Request.Timeout = 0;
- memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB));
- BUG_ON(cmd->cmd_len > sizeof(cp->Request.CDB));
- cp->Request.CDBLen = cmd->cmd_len;
- memcpy(cp->Request.CDB, cmd->cmnd, cmd->cmd_len);
- cp->Request.Type.Type = TYPE_CMD;
- cp->Request.Type.Attribute = ATTR_SIMPLE;
- switch(cmd->sc_data_direction)
- {
- case DMA_TO_DEVICE: cp->Request.Type.Direction = XFER_WRITE; break;
- case DMA_FROM_DEVICE: cp->Request.Type.Direction = XFER_READ; break;
- case DMA_NONE: cp->Request.Type.Direction = XFER_NONE; break;
- case DMA_BIDIRECTIONAL:
- // This can happen if a buggy application does a scsi passthru
- // and sets both inlen and outlen to non-zero. ( see
- // ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
- cp->Request.Type.Direction = XFER_RSVD;
- // This is technically wrong, and cciss controllers should
- // reject it with CMD_INVALID, which is the most correct
- // response, but non-fibre backends appear to let it
- // slide by, and give the same results as if this field
- // were set correctly. Either way is acceptable for
- // our purposes here.
- break;
- default:
- printk("cciss: unknown data direction: %d\n",
- cmd->sc_data_direction);
- BUG();
- break;
- }
- cciss_scatter_gather((*c)->pdev, cp, cmd); // Fill the SG list
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&(*c)->reqQ, cp);
- (*c)->Qdepth++;
- start_io(*c);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- /* the cmd'll come back via intr handler in complete_scsi_command() */
- return 0;
- }
- static void
- cciss_unregister_scsi(int ctlr)
- {
- struct cciss_scsi_adapter_data_t *sa;
- struct cciss_scsi_cmd_stack_t *stk;
- unsigned long flags;
- /* we are being forcibly unloaded, and may not refuse. */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
- stk = &sa->cmd_stack;
- /* if we weren't ever actually registered, don't unregister */
- if (sa->registered) {
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- scsi_remove_host(sa->scsi_host);
- scsi_host_put(sa->scsi_host);
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- }
- /* set scsi_host to NULL so our detect routine will
- find us on register */
- sa->scsi_host = NULL;
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- scsi_cmd_stack_free(ctlr);
- kfree(sa);
- }
- static int
- cciss_engage_scsi(int ctlr)
- {
- struct cciss_scsi_adapter_data_t *sa;
- struct cciss_scsi_cmd_stack_t *stk;
- unsigned long flags;
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr;
- stk = &sa->cmd_stack;
- if (sa->registered) {
- printk("cciss%d: SCSI subsystem already engaged.\n", ctlr);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- return ENXIO;
- }
- sa->registered = 1;
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- cciss_update_non_disk_devices(ctlr, -1);
- cciss_scsi_detect(ctlr);
- return 0;
- }
- static void
- cciss_seq_tape_report(struct seq_file *seq, int ctlr)
- {
- unsigned long flags;
- CPQ_TAPE_LOCK(ctlr, flags);
- seq_printf(seq,
- "Sequential access devices: %d\n\n",
- ccissscsi[ctlr].ndevices);
- CPQ_TAPE_UNLOCK(ctlr, flags);
- }
- /* Need at least one of these error handlers to keep ../scsi/hosts.c from
- * complaining. Doing a host- or bus-reset can't do anything good here.
- * Despite what it might say in scsi_error.c, there may well be commands
- * on the controller, as the cciss driver registers twice, once as a block
- * device for the logical drives, and once as a scsi device, for any tape
- * drives. So we know there are no commands out on the tape drives, but we
- * don't know there are no commands on the controller, and it is likely
- * that there probably are, as the cciss block device is most commonly used
- * as a boot device (embedded controller on HP/Compaq systems.)
- */
- static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
- {
- int rc;
- CommandList_struct *cmd_in_trouble;
- ctlr_info_t **c;
- int ctlr;
- /* find the controller to which the command to be aborted was sent */
- c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
- if (c == NULL) /* paranoia */
- return FAILED;
- ctlr = (*c)->ctlr;
- printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
- /* find the command that's giving us trouble */
- cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
- if (cmd_in_trouble == NULL) { /* paranoia */
- return FAILED;
- }
- /* send a reset to the SCSI LUN which the command was sent to */
- rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0,
- (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0],
- TYPE_MSG);
- /* sendcmd turned off interrupts on the board, turn 'em back on. */
- (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
- if (rc == 0)
- return SUCCESS;
- printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
- return FAILED;
- }
- static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
- {
- int rc;
- CommandList_struct *cmd_to_abort;
- ctlr_info_t **c;
- int ctlr;
- /* find the controller to which the command to be aborted was sent */
- c = (ctlr_info_t **) &scsicmd->device->host->hostdata[0];
- if (c == NULL) /* paranoia */
- return FAILED;
- ctlr = (*c)->ctlr;
- printk(KERN_WARNING "cciss%d: aborting tardy SCSI cmd\n", ctlr);
- /* find the command to be aborted */
- cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;
- if (cmd_to_abort == NULL) /* paranoia */
- return FAILED;
- rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag,
- 0, 2, 0, 0,
- (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0],
- TYPE_MSG);
- /* sendcmd turned off interrupts on the board, turn 'em back on. */
- (*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
- if (rc == 0)
- return SUCCESS;
- return FAILED;
- }
- #else /* no CONFIG_CISS_SCSI_TAPE */
- /* If no tape support, then these become defined out of existence */
- #define cciss_scsi_setup(cntl_num)
- #endif /* CONFIG_CISS_SCSI_TAPE */
|