# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	v2.6.0-test10 -> 1.1489 
#	drivers/scsi/libata-core.c	1.6     -> 1.7    
#	drivers/scsi/scsi_error.c	1.65    -> 1.66   
#	include/linux/libata.h	1.3     -> 1.4    
#	include/scsi/scsi_device.h	1.10    -> 1.11   
#	       kernel/fork.c	1.145   -> 1.146  
#	drivers/scsi/scsi_sysfs.c	1.36    -> 1.38   
#	drivers/scsi/libata.h	1.2     -> 1.3    
#	net/econet/af_econet.c	1.27    -> 1.28   
#	drivers/scsi/scsi_lib.c	1.114   -> 1.115  
#	 drivers/scsi/scsi.c	1.130   -> 1.131  
#	 fs/jfs/jfs_logmgr.c	1.50    -> 1.51   
#	drivers/scsi/sata_svw.c	1.2     -> 1.4    
#	 drivers/net/pppoe.c	1.35    -> 1.36   
#	drivers/scsi/scsi_priv.h	1.28    -> 1.29   
#	drivers/scsi/sata_promise.c	1.12    -> 1.13   
#	  include/net/sock.h	1.46    -> 1.47   
#	drivers/scsi/scsi_scan.c	1.112   -> 1.114  
#	    net/ipv6/mcast.c	1.46    -> 1.47   
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/11/23	torvalds@home.osdl.org	1.1481.2.2
# Linux 2.6.0-test10
# --------------------------------------------
# 03/11/23	dlstevens@us.ibm.com	1.1481.2.3
# [IPV6]: Multicast output bypasses netfilter hooks, fix.
# 
# Noted by Harald Welte (laforge@netfilter.org)
# --------------------------------------------
# 03/11/24	jgarzik@redhat.com	1.1481.1.3
# Merge redhat.com:/spare/repo/linux-2.5
# into redhat.com:/spare/repo/libata-2.5
# --------------------------------------------
# 03/11/24	jejb@raven.il.steeleye.com	1.1484
# Fix locking problems in scsi_report_bus_reset() causing aic7xxx to hang
# 
# All the users of this function in the SCSI tree call it with the host
# lock held.  With the new list traversal code, it was trying to take
# the lock again to traverse the list.
# 
# Fix it to use the unlocked version of list traversal and modify the
# header comments to make it clear that the lock is expected to be held
# on calling it.
# --------------------------------------------
# 03/11/24	benh@kernel.crashing.org	1.1481.1.4
# [libata] Fix flush of Device Control register to device
# 
# Also add some ServerWorks-specific tweaks.
# --------------------------------------------
# 03/11/24	jgarzik@redhat.com	1.1481.1.5
# [libata] bump versions for core and serverworks driver
# --------------------------------------------
# 03/11/24	torvalds@home.osdl.org	1.1485
# Merge bk://linux-scsi.bkbits.net/scsi-bugfixes-2.6
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/11/24	davem@nuts.ninka.net	1.1481.2.4
# [NET]: In sock_queue_rcv_skb(), do not deref skb->len after it is queued to the socket.
# 
# In implementations that use no socket locking, such as RAW sockets,
# once we queue the SKB to the socket another cpu can remove the SKB
# from the socket queue and free up the SKB making the skb->len access
# touch freed memory.
# 
# Based upon a report from Burton Windle, kernel bugzilla #937
# --------------------------------------------
# 03/11/24	davem@nuts.ninka.net	1.1481.2.5
# [PPPOE]: Do not leak SKB if sock_queue_rcv_skb() fails.
# --------------------------------------------
# 03/11/24	davem@nuts.ninka.net	1.1481.2.6
# [ECONET]: Do not leak SKBs if ec_queue_packet() fails.
# 
# Also, make sure NET_RX_DROP is returned if we did not accept the
# packet.
# --------------------------------------------
# 03/11/24	torvalds@home.osdl.org	1.1486
# Merge master.kernel.org:/home/davem/BK/net-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
# 03/11/25	torvalds@home.osdl.org	1.1487
# Fix error return on concurrent fork() with threaded exit()
# --------------------------------------------
# 03/11/25	shaggy@austin.ibm.com	1.1488
# [PATCH] JFS: Avoid segfault when dirty inodes are written on readonly mount
# 
# This fixes an oops that can occur if JFS is used as the root filesystem.
# 
# Writes to a device node may cause a ->write_inode to be called during a
# read-only mount.  JFS needs to check for NULL log in jfs_flush_journal. 
# --------------------------------------------
# 03/11/25	torvalds@home.osdl.org	1.1489
# Merge bk://gkernel.bkbits.net/libata-2.5
# into home.osdl.org:/home/torvalds/v2.5/linux
# --------------------------------------------
#
diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c
--- a/drivers/net/pppoe.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/net/pppoe.c	Tue Nov 25 19:25:22 2003
@@ -352,7 +352,8 @@
 		if (!__pppoe_xmit( relay_po->sk, skb))
 			goto abort_put;
 	} else {
-		sock_queue_rcv_skb(sk, skb);
+		if (sock_queue_rcv_skb(sk, skb))
+			goto abort_kfree;
 	}
 
 	return NET_RX_SUCCESS;
diff -Nru a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
--- a/drivers/scsi/libata-core.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/libata-core.c	Tue Nov 25 19:25:22 2003
@@ -133,7 +133,11 @@
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
 
-	outb(tf->ctl, ioaddr->ctl_addr);
+	if (tf->ctl != ap->last_ctl) {
+		outb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
 
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
 		outb(tf->hob_feature, ioaddr->error_addr);
@@ -187,7 +191,11 @@
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
 
-	writeb(tf->ctl, ap->ioaddr.ctl_addr);
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, ap->ioaddr.ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
 
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
 		writeb(tf->hob_feature, (void *) ioaddr->error_addr);
@@ -1281,9 +1289,9 @@
 	/* software reset.  causes dev0 to be selected */
 	if (ap->flags & ATA_FLAG_MMIO) {
 		writeb(ap->ctl, ioaddr->ctl_addr);
-		udelay(10);	/* FIXME: flush */
+		udelay(20);	/* FIXME: flush */
 		writeb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
-		udelay(10);	/* FIXME: flush */
+		udelay(20);	/* FIXME: flush */
 		writeb(ap->ctl, ioaddr->ctl_addr);
 	} else {
 		outb(ap->ctl, ioaddr->ctl_addr);
@@ -2755,6 +2763,7 @@
 	ap->cbl = ATA_CBL_NONE;
 	ap->device[0].flags = ATA_DFLAG_MASTER;
 	ap->active_tag = ATA_TAG_POISON;
+	ap->last_ctl = 0xFF;
 
 	/* ata_engine init */
 	ap->eng.flags = 0;
diff -Nru a/drivers/scsi/libata.h b/drivers/scsi/libata.h
--- a/drivers/scsi/libata.h	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/libata.h	Tue Nov 25 19:25:22 2003
@@ -26,7 +26,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME	"libata"
-#define DRV_VERSION	"0.80"	/* must be exactly four chars */
+#define DRV_VERSION	"0.81"	/* must be exactly four chars */
 
 struct ata_scsi_args {
 	struct ata_port		*ap;
diff -Nru a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
--- a/drivers/scsi/sata_promise.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/sata_promise.c	Tue Nov 25 19:25:22 2003
@@ -213,6 +213,8 @@
 	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
 	{ PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 	  board_20319 },
 	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
diff -Nru a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
--- a/drivers/scsi/sata_svw.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/sata_svw.c	Tue Nov 25 19:25:22 2003
@@ -44,7 +44,7 @@
 #endif /* CONFIG_ALL_PPC */
 
 #define DRV_NAME	"ata_k2"
-#define DRV_VERSION	"1.02"
+#define DRV_VERSION	"1.03"
 
 
 static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
@@ -69,8 +69,11 @@
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
 
-	writeb(tf->ctl, ioaddr->ctl_addr);
-
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
 	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
 		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->error_addr);
 		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
@@ -311,13 +314,24 @@
 		rc = -ENODEV;
 		goto err_out_unmap;
 	}
+
+	/* Clear a magic bit in SCR1 according to Darwin, those help
+	 * some funky seagate drives (though so far, those were already
+	 * set by the firmware on the machines I had access to
+	 */
+	writel(readl(mmio_base + 0x80) & ~0x00040000, mmio_base + 0x80);
+
+	/* Clear SATA error & interrupts we don't use */
+	writel(0xffffffff, mmio_base + 0x44);
+	writel(0x0, mmio_base + 0x88);
+
 	probe_ent->sht = &k2_sata_sht;
-	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				ATA_FLAG_SRST | ATA_FLAG_MMIO;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+				ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
 	probe_ent->port_ops = &k2_sata_ops;
-       	probe_ent->n_ports = 2;
-       	probe_ent->irq = pdev->irq;
-       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
 	probe_ent->mmio_base = mmio_base;
 
 	/*
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi.c	Tue Nov 25 19:25:22 2003
@@ -367,6 +367,16 @@
 	unsigned long timeout;
 	int rtn = 0;
 
+	/* check if the device is still usable */
+	if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
+		/* in SDEV_DEL we error all commands. DID_NO_CONNECT
+		 * returns an immediate error upwards, and signals
+		 * that the device is no longer present */
+		cmd->result = DID_NO_CONNECT << 16;
+		scsi_done(cmd);
+		/* return 0 (because the command has been processed) */
+		goto out;
+	}
 	/* Assign a unique nonzero serial_number. */
 	/* XXX(hch): this is racy */
 	if (++serial_number == 0)
@@ -893,7 +903,7 @@
  */
 int scsi_device_get(struct scsi_device *sdev)
 {
-	if (test_bit(SDEV_DEL, &sdev->sdev_state))
+	if (sdev->sdev_state == SDEV_DEL)
 		return -ENXIO;
 	if (!get_device(&sdev->sdev_gendev))
 		return -ENXIO;
@@ -1015,7 +1025,7 @@
 	struct list_head *lh, *lh_sf;
 	unsigned long flags;
 
-	set_bit(SDEV_CANCEL, &sdev->sdev_state);
+	sdev->sdev_state = SDEV_CANCEL;
 
 	spin_lock_irqsave(&sdev->list_lock, flags);
 	list_for_each_entry(scmd, &sdev->cmd_list, list) {
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi_error.c	Tue Nov 25 19:25:22 2003
@@ -911,7 +911,9 @@
 
 	if (rtn == SUCCESS) {
 		scsi_sleep(BUS_RESET_SETTLE_TIME);
+		spin_lock_irqsave(scmd->device->host->host_lock, flags);
 		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
+		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
 	}
 
 	return rtn;
@@ -940,7 +942,9 @@
 
 	if (rtn == SUCCESS) {
 		scsi_sleep(HOST_RESET_SETTLE_TIME);
+		spin_lock_irqsave(scmd->device->host->host_lock, flags);
 		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
+		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
 	}
 
 	return rtn;
@@ -1608,7 +1612,7 @@
  *
  * Returns:     Nothing
  *
- * Lock status: No locks are assumed held.
+ * Lock status: Host lock must be held.
  *
  * Notes:       This only needs to be called if the reset is one which
  *		originates from an unknown location.  Resets originated
@@ -1622,7 +1626,7 @@
 {
 	struct scsi_device *sdev;
 
-	shost_for_each_device(sdev, shost) {
+	__shost_for_each_device(sdev, shost) {
 		if (channel == sdev->channel) {
 			sdev->was_reset = 1;
 			sdev->expecting_cc_ua = 1;
@@ -1642,7 +1646,7 @@
  *
  * Returns:     Nothing
  *
- * Lock status: No locks are assumed held.
+ * Lock status: Host lock must be held
  *
  * Notes:       This only needs to be called if the reset is one which
  *		originates from an unknown location.  Resets originated
@@ -1656,7 +1660,7 @@
 {
 	struct scsi_device *sdev;
 
-	shost_for_each_device(sdev, shost) {
+	__shost_for_each_device(sdev, shost) {
 		if (channel == sdev->channel &&
 		    target == sdev->id) {
 			sdev->was_reset = 1;
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi_lib.c	Tue Nov 25 19:25:22 2003
@@ -923,6 +923,22 @@
 {
 	struct scsi_device *sdev = q->queuedata;
 	struct scsi_cmnd *cmd;
+	int specials_only = 0;
+
+	if(unlikely(sdev->sdev_state != SDEV_RUNNING)) {
+		/* OK, we're not in a running state don't prep
+		 * user commands */
+		if(sdev->sdev_state == SDEV_DEL) {
+			/* Device is fully deleted, no commands
+			 * at all allowed down */
+			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
+			       sdev->host->host_no, sdev->id, sdev->lun);
+			return BLKPREP_KILL;
+		}
+		/* OK, we only allow special commands (i.e. not
+		 * user initiated ones */
+		specials_only = 1;
+	}
 
 	/*
 	 * Find the actual device driver associated with this command.
@@ -945,6 +961,14 @@
 		} else
 			cmd = req->special;
 	} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+
+		if(unlikely(specials_only)) {
+			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
+			       sdev->host->host_no, sdev->id, sdev->lun);
+			return BLKPREP_KILL;
+		}
+			
+			
 		/*
 		 * Just check to see if the device is online.  If
 		 * it isn't, we refuse to process ordinary commands
@@ -1127,6 +1151,10 @@
 	struct scsi_cmnd *cmd;
 	struct request *req;
 
+	if(!get_device(&sdev->sdev_gendev))
+		/* We must be tearing the block queue down already */
+		return;
+
 	/*
 	 * To start with, we keep looping until the queue is empty, or until
 	 * the host is no longer able to accept any more requests.
@@ -1199,7 +1227,7 @@
 		}
 	}
 
-	return;
+	goto out;
 
  not_ready:
 	spin_unlock_irq(shost->host_lock);
@@ -1217,6 +1245,12 @@
 	sdev->device_busy--;
 	if(sdev->device_busy == 0)
 		blk_plug_device(q);
+ out:
+	/* must be careful here...if we trigger the ->remove() function
+	 * we cannot be holding the q lock */
+	spin_unlock_irq(q->queue_lock);
+	put_device(&sdev->sdev_gendev);
+	spin_lock_irq(q->queue_lock);
 }
 
 u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- a/drivers/scsi/scsi_priv.h	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi_priv.h	Tue Nov 25 19:25:22 2003
@@ -130,7 +130,6 @@
 extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int,
 				   unsigned int, unsigned int, int);
 extern void scsi_forget_host(struct Scsi_Host *);
-extern void scsi_free_sdev(struct scsi_device *);
 extern void scsi_rescan_device(struct device *);
 
 /* scsi_sysctl.c */
@@ -143,7 +142,8 @@
 #endif /* CONFIG_SYSCTL */
 
 /* scsi_sysfs.c */
-extern int scsi_device_register(struct scsi_device *);
+extern void scsi_device_dev_release(struct device *);
+extern int scsi_sysfs_add_sdev(struct scsi_device *);
 extern int scsi_sysfs_add_host(struct Scsi_Host *);
 extern int scsi_sysfs_register(void);
 extern void scsi_sysfs_unregister(void);
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi_scan.c	Tue Nov 25 19:25:22 2003
@@ -205,6 +205,7 @@
 	sdev->lun = lun;
 	sdev->channel = channel;
 	sdev->online = TRUE;
+	sdev->sdev_state = SDEV_CREATED;
 	INIT_LIST_HEAD(&sdev->siblings);
 	INIT_LIST_HEAD(&sdev->same_target_siblings);
 	INIT_LIST_HEAD(&sdev->cmd_list);
@@ -236,6 +237,25 @@
 			goto out_free_queue;
 	}
 
+	if (get_device(&sdev->host->shost_gendev)) {
+
+		device_initialize(&sdev->sdev_gendev);
+		sdev->sdev_gendev.parent = &sdev->host->shost_gendev;
+		sdev->sdev_gendev.bus = &scsi_bus_type;
+		sdev->sdev_gendev.release = scsi_device_dev_release;
+		sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
+			sdev->host->host_no, sdev->channel, sdev->id,
+			sdev->lun);
+
+		class_device_initialize(&sdev->sdev_classdev);
+		sdev->sdev_classdev.dev = &sdev->sdev_gendev;
+		sdev->sdev_classdev.class = &sdev_class;
+		snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
+			 "%d:%d:%d:%d", sdev->host->host_no,
+			 sdev->channel, sdev->id, sdev->lun);
+	} else
+		goto out_free_queue;
+
 	/*
 	 * If there are any same target siblings, add this to the
 	 * sibling list
@@ -273,36 +293,6 @@
 }
 
 /**
- * scsi_free_sdev - cleanup and free a scsi_device
- * @sdev:	cleanup and free this scsi_device
- *
- * Description:
- *     Undo the actions in scsi_alloc_sdev, including removing @sdev from
- *     the list, and freeing @sdev.
- **/
-void scsi_free_sdev(struct scsi_device *sdev)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(sdev->host->host_lock, flags);
-	list_del(&sdev->siblings);
-	list_del(&sdev->same_target_siblings);
-	spin_unlock_irqrestore(sdev->host->host_lock, flags);
-
-	if (sdev->request_queue)
-		scsi_free_queue(sdev->request_queue);
-
-	spin_lock_irqsave(sdev->host->host_lock, flags);
-	list_del(&sdev->starved_entry);
-	if (sdev->single_lun && --sdev->sdev_target->starget_refcnt == 0)
-		kfree(sdev->sdev_target);
-	spin_unlock_irqrestore(sdev->host->host_lock, flags);
-
-	kfree(sdev->inquiry);
-	kfree(sdev);
-}
-
-/**
  * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
  * @sreq:	used to send the INQUIRY
  * @inq_result:	area to store the INQUIRY result
@@ -642,7 +632,7 @@
 	 * register it and tell the rest of the kernel
 	 * about it.
 	 */
-	scsi_device_register(sdev);
+	scsi_sysfs_add_sdev(sdev);
 
 	return SCSI_SCAN_LUN_PRESENT;
 }
@@ -748,8 +738,11 @@
 	if (res == SCSI_SCAN_LUN_PRESENT) {
 		if (sdevp)
 			*sdevp = sdev;
-	} else
-		scsi_free_sdev(sdev);
+	} else {
+		if (sdev->host->hostt->slave_destroy)
+			sdev->host->hostt->slave_destroy(sdev);
+		put_device(&sdev->sdev_gendev);
+	}
  out:
 	return res;
 }
@@ -1301,5 +1294,8 @@
 void scsi_free_host_dev(struct scsi_device *sdev)
 {
 	BUG_ON(sdev->id != sdev->host->this_id);
-	scsi_free_sdev(sdev);
+
+	if (sdev->host->hostt->slave_destroy)
+		sdev->host->hostt->slave_destroy(sdev);
+	put_device(&sdev->sdev_gendev);
 }
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Tue Nov 25 19:25:22 2003
+++ b/drivers/scsi/scsi_sysfs.c	Tue Nov 25 19:25:22 2003
@@ -115,14 +115,29 @@
 	put_device(&sdev->sdev_gendev);
 }
 
-static void scsi_device_dev_release(struct device *dev)
+void scsi_device_dev_release(struct device *dev)
 {
 	struct scsi_device *sdev;
 	struct device *parent;
+	unsigned long flags;
 
 	parent = dev->parent;
 	sdev = to_scsi_device(dev);
-	scsi_free_sdev(sdev);
+
+	spin_lock_irqsave(sdev->host->host_lock, flags);
+	list_del(&sdev->siblings);
+	list_del(&sdev->same_target_siblings);
+	list_del(&sdev->starved_entry);
+	if (sdev->single_lun && --sdev->sdev_target->starget_refcnt == 0)
+		kfree(sdev->sdev_target);
+	spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
+	if (sdev->request_queue)
+		scsi_free_queue(sdev->request_queue);
+
+	kfree(sdev->inquiry);
+	kfree(sdev);
+
 	put_device(parent);
 }
 
@@ -321,29 +336,20 @@
 }
 
 /**
- * scsi_device_register - register a scsi device with the scsi bus
- * @sdev:	scsi_device to register
+ * scsi_sysfs_add_sdev - add scsi device to sysfs
+ * @sdev:	scsi_device to add
  *
  * Return value:
  * 	0 on Success / non-zero on Failure
  **/
-int scsi_device_register(struct scsi_device *sdev)
+int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
-	int error = 0, i;
+	int error = -EINVAL, i;
+
+	if (sdev->sdev_state != SDEV_CREATED)
+		return error;
 
-	set_bit(SDEV_ADD, &sdev->sdev_state);
-	device_initialize(&sdev->sdev_gendev);
-	sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
-		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
-	sdev->sdev_gendev.parent = &sdev->host->shost_gendev;
-	sdev->sdev_gendev.bus = &scsi_bus_type;
-	sdev->sdev_gendev.release = scsi_device_dev_release;
-
-	class_device_initialize(&sdev->sdev_classdev);
-	sdev->sdev_classdev.dev = &sdev->sdev_gendev;
-	sdev->sdev_classdev.class = &sdev_class;
-	snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d",
-		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+	sdev->sdev_state = SDEV_RUNNING;
 
 	error = device_add(&sdev->sdev_gendev);
 	if (error) {
@@ -351,8 +357,6 @@
 		return error;
 	}
 
-	get_device(sdev->sdev_gendev.parent);
-
 	error = class_device_add(&sdev->sdev_classdev);
 	if (error) {
 		printk(KERN_INFO "error 2\n");
@@ -384,8 +388,11 @@
 	return error;
 
 clean_device:
+	sdev->sdev_state = SDEV_CANCEL;
+
 	device_del(&sdev->sdev_gendev);
 	put_device(&sdev->sdev_gendev);
+
 	return error;
 
 }
@@ -396,12 +403,14 @@
  **/
 void scsi_remove_device(struct scsi_device *sdev)
 {
-	class_device_unregister(&sdev->sdev_classdev);
-	set_bit(SDEV_DEL, &sdev->sdev_state);
-	if (sdev->host->hostt->slave_destroy)
-		sdev->host->hostt->slave_destroy(sdev);
-	device_del(&sdev->sdev_gendev);
-	put_device(&sdev->sdev_gendev);
+	if (sdev->sdev_state == SDEV_RUNNING || sdev->sdev_state == SDEV_CANCEL) {
+		sdev->sdev_state = SDEV_DEL;
+		class_device_unregister(&sdev->sdev_classdev);
+		device_del(&sdev->sdev_gendev);
+		if (sdev->host->hostt->slave_destroy)
+			sdev->host->hostt->slave_destroy(sdev);
+		put_device(&sdev->sdev_gendev);
+	}
 }
 
 int scsi_register_driver(struct device_driver *drv)
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Tue Nov 25 19:25:22 2003
+++ b/fs/jfs/jfs_logmgr.c	Tue Nov 25 19:25:22 2003
@@ -1415,6 +1415,10 @@
 	int i;
 	struct tblock *target;
 
+	/* jfs_write_inode may call us during read-only mount */
+	if (!log)
+		return;
+
 	jfs_info("jfs_flush_journal: log:0x%p wait=%d", log, wait);
 
 	LOGGC_LOCK(log);
diff -Nru a/include/linux/libata.h b/include/linux/libata.h
--- a/include/linux/libata.h	Tue Nov 25 19:25:22 2003
+++ b/include/linux/libata.h	Tue Nov 25 19:25:22 2003
@@ -310,6 +310,7 @@
 	struct ata_ioports	ioaddr;	/* ATA cmd/ctl/dma register blocks */
 
 	u8			ctl;	/* cache of ATA control register */
+	u8			last_ctl;	/* Cache last written value */
 	unsigned int		bus_state;
 	unsigned int		port_state;
 	unsigned int		pio_mask;
@@ -522,12 +523,12 @@
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 
 	ap->ctl &= ~ATA_NIEN;
+	ap->last_ctl = ap->ctl;
 
 	if (ap->flags & ATA_FLAG_MMIO)
 		writeb(ap->ctl, ioaddr->ctl_addr);
 	else
 		outb(ap->ctl, ioaddr->ctl_addr);
-
 	return ata_wait_idle(ap);
 }
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Tue Nov 25 19:25:22 2003
+++ b/include/net/sock.h	Tue Nov 25 19:25:22 2003
@@ -917,6 +917,7 @@
 static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
 	int err = 0;
+	int skb_len;
 
 	/* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
 	   number of warnings when compiling with -W --ANK
@@ -937,9 +938,18 @@
 
 	skb->dev = NULL;
 	skb_set_owner_r(skb, sk);
+
+	/* Cache the SKB length before we tack it onto the receive
+	 * queue.  Once it is added it no longer belongs to us and
+	 * may be freed by other threads of control pulling packets
+	 * from the queue.
+	 */
+	skb_len = skb->len;
+
 	skb_queue_tail(&sk->sk_receive_queue, skb);
+
 	if (!sock_flag(sk, SOCK_DEAD))
-		sk->sk_data_ready(sk, skb->len);
+		sk->sk_data_ready(sk, skb_len);
 out:
 	return err;
 }
diff -Nru a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
--- a/include/scsi/scsi_device.h	Tue Nov 25 19:25:22 2003
+++ b/include/scsi/scsi_device.h	Tue Nov 25 19:25:22 2003
@@ -14,11 +14,15 @@
 /*
  * sdev state
  */
-enum {
-	SDEV_ADD,
-	SDEV_DEL,
-	SDEV_CANCEL,
-	SDEV_RECOVERY,
+enum scsi_device_state {
+	SDEV_CREATED,		/* device created but not added to sysfs
+				 * Only internal commands allowed (for inq) */
+	SDEV_RUNNING,		/* device properly configured
+				 * All commands allowed */
+	SDEV_CANCEL,		/* beginning to delete device
+				 * Only error handler commands allowed */
+	SDEV_DEL,		/* device deleted 
+				 * no commands allowed */
 };
 
 struct scsi_device {
@@ -99,7 +103,7 @@
 	struct device		sdev_gendev;
 	struct class_device	sdev_classdev;
 
-	unsigned long sdev_state;
+	enum scsi_device_state sdev_state;
 };
 #define	to_scsi_device(d)	\
 	container_of(d, struct scsi_device, sdev_gendev)
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Tue Nov 25 19:25:22 2003
+++ b/kernel/fork.c	Tue Nov 25 19:25:22 2003
@@ -1014,6 +1014,7 @@
 		if (current->signal->group_exit) {
 			spin_unlock(&current->sighand->siglock);
 			write_unlock_irq(&tasklist_lock);
+			retval = -EAGAIN;
 			goto bad_fork_cleanup_namespace;
 		}
 		p->tgid = current->tgid;
diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c	Tue Nov 25 19:25:22 2003
+++ b/net/econet/af_econet.c	Tue Nov 25 19:25:22 2003
@@ -1041,12 +1041,15 @@
 	if (!sk)
 		goto drop;
 
-	return ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb, 
-			       hdr->port);
+	if (ec_queue_packet(sk, skb, edev->net, hdr->src_stn, hdr->cb,
+			    hdr->port))
+		goto drop;
+
+	return 0;
 
 drop:
 	kfree_skb(skb);
-	return 0;
+	return NET_RX_DROP;
 }
 
 static struct packet_type econet_packet_type = {
diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c
--- a/net/ipv6/mcast.c	Tue Nov 25 19:25:22 2003
+++ b/net/ipv6/mcast.c	Tue Nov 25 19:25:22 2003
@@ -47,6 +47,9 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+
 #include <net/sock.h>
 #include <net/snmp.h>
 
@@ -1270,6 +1273,7 @@
 	struct mld2_report *pmr = (struct mld2_report *)skb->h.raw;
 	int payload_len, mldlen;
 	struct inet6_dev *idev = in6_dev_get(skb->dev);
+	int err;
 
 	payload_len = skb->tail - (unsigned char *)skb->nh.ipv6h -
 		sizeof(struct ipv6hdr);
@@ -1278,8 +1282,10 @@
 
 	pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen,
 		IPPROTO_ICMPV6, csum_partial(skb->h.raw, mldlen, 0));
-	dev_queue_xmit(skb);
-	ICMP6_INC_STATS(idev,Icmp6OutMsgs);
+	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
+		dev_queue_xmit);
+	if (!err)
+		ICMP6_INC_STATS(idev,Icmp6OutMsgs);
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
 }
@@ -1608,12 +1614,15 @@
 
 	idev = in6_dev_get(skb->dev);
 
-	dev_queue_xmit(skb);
-	if (type == ICMPV6_MGM_REDUCTION)
-		ICMP6_INC_STATS(idev, Icmp6OutGroupMembReductions);
-	else
-		ICMP6_INC_STATS(idev, Icmp6OutGroupMembResponses);
-	ICMP6_INC_STATS(idev, Icmp6OutMsgs);
+	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,
+		dev_queue_xmit);
+	if (!err) {
+		if (type == ICMPV6_MGM_REDUCTION)
+			ICMP6_INC_STATS(idev, Icmp6OutGroupMembReductions);
+		else
+			ICMP6_INC_STATS(idev, Icmp6OutGroupMembResponses);
+		ICMP6_INC_STATS(idev, Icmp6OutMsgs);
+	}
 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);