@@ -510,22 +510,34 @@ void scsi_attach_vpd(struct scsi_device *sdev)
510510 return ;
511511
512512 for (i = 4 ; i < vpd_buf -> len ; i ++ ) {
513- if (vpd_buf -> data [i ] == 0x0 )
513+ switch (vpd_buf -> data [i ]) {
514+ case 0x0 :
514515 scsi_update_vpd_page (sdev , 0x0 , & sdev -> vpd_pg0 );
515- if (vpd_buf -> data [i ] == 0x80 )
516+ break ;
517+ case 0x80 :
516518 scsi_update_vpd_page (sdev , 0x80 , & sdev -> vpd_pg80 );
517- if (vpd_buf -> data [i ] == 0x83 )
519+ break ;
520+ case 0x83 :
518521 scsi_update_vpd_page (sdev , 0x83 , & sdev -> vpd_pg83 );
519- if (vpd_buf -> data [i ] == 0x89 )
522+ break ;
523+ case 0x89 :
520524 scsi_update_vpd_page (sdev , 0x89 , & sdev -> vpd_pg89 );
521- if (vpd_buf -> data [i ] == 0xb0 )
525+ break ;
526+ case 0xb0 :
522527 scsi_update_vpd_page (sdev , 0xb0 , & sdev -> vpd_pgb0 );
523- if (vpd_buf -> data [i ] == 0xb1 )
528+ break ;
529+ case 0xb1 :
524530 scsi_update_vpd_page (sdev , 0xb1 , & sdev -> vpd_pgb1 );
525- if (vpd_buf -> data [i ] == 0xb2 )
531+ break ;
532+ case 0xb2 :
526533 scsi_update_vpd_page (sdev , 0xb2 , & sdev -> vpd_pgb2 );
527- if (vpd_buf -> data [i ] == 0xb7 )
534+ break ;
535+ case 0xb7 :
528536 scsi_update_vpd_page (sdev , 0xb7 , & sdev -> vpd_pgb7 );
537+ break ;
538+ default :
539+ break ;
540+ }
529541 }
530542 kfree (vpd_buf );
531543}
@@ -695,26 +707,23 @@ void scsi_cdl_check(struct scsi_device *sdev)
695707 */
696708int scsi_cdl_enable (struct scsi_device * sdev , bool enable )
697709{
698- struct scsi_mode_data data ;
699- struct scsi_sense_hdr sshdr ;
700- struct scsi_vpd * vpd ;
701- bool is_ata = false;
702710 char buf [64 ];
711+ bool is_ata ;
703712 int ret ;
704713
705714 if (!sdev -> cdl_supported )
706715 return - EOPNOTSUPP ;
707716
708717 rcu_read_lock ();
709- vpd = rcu_dereference (sdev -> vpd_pg89 );
710- if (vpd )
711- is_ata = true;
718+ is_ata = rcu_dereference (sdev -> vpd_pg89 );
712719 rcu_read_unlock ();
713720
714721 /*
715722 * For ATA devices, CDL needs to be enabled with a SET FEATURES command.
716723 */
717724 if (is_ata ) {
725+ struct scsi_mode_data data ;
726+ struct scsi_sense_hdr sshdr ;
718727 char * buf_data ;
719728 int len ;
720729
@@ -723,16 +732,30 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
723732 if (ret )
724733 return - EINVAL ;
725734
726- /* Enable CDL using the ATA feature page */
735+ /* Enable or disable CDL using the ATA feature page */
727736 len = min_t (size_t , sizeof (buf ),
728737 data .length - data .header_length -
729738 data .block_descriptor_length );
730739 buf_data = buf + data .header_length +
731740 data .block_descriptor_length ;
732- if (enable )
733- buf_data [4 ] = 0x02 ;
734- else
735- buf_data [4 ] = 0 ;
741+
742+ /*
743+ * If we want to enable CDL and CDL is already enabled on the
744+ * device, do nothing. This avoids needlessly resetting the CDL
745+ * statistics on the device as that is implied by the CDL enable
746+ * action. Similar to this, there is no need to do anything if
747+ * we want to disable CDL and CDL is already disabled.
748+ */
749+ if (enable ) {
750+ if ((buf_data [4 ] & 0x03 ) == 0x02 )
751+ goto out ;
752+ buf_data [4 ] &= ~0x03 ;
753+ buf_data [4 ] |= 0x02 ;
754+ } else {
755+ if ((buf_data [4 ] & 0x03 ) == 0x00 )
756+ goto out ;
757+ buf_data [4 ] &= ~0x03 ;
758+ }
736759
737760 ret = scsi_mode_select (sdev , 1 , 0 , buf_data , len , 5 * HZ , 3 ,
738761 & data , & sshdr );
@@ -744,6 +767,7 @@ int scsi_cdl_enable(struct scsi_device *sdev, bool enable)
744767 }
745768 }
746769
770+ out :
747771 sdev -> cdl_enable = enable ;
748772
749773 return 0 ;
0 commit comments